TypeScript中的服务器发送事件:轻松实现数据流
\n\n想象一下:您的服务器生成数据——日志、通知、汇率更新——并且需要立即将它们发送到前端。WebSocket?功能强大但过于冗余。轮询?速度慢且消耗流量。还有第三条路——优雅、简单且极其有用:服务器发送事件(SSE)。
\n\n在本文中,我们将从头到尾剖析TypeScript中的SSE。我们将编写客户端和服务器,学习如何处理错误和重新连接,最重要的是,理解SSE何时真正优于其他方法。开始吧!
\n\n什么是服务器发送事件以及为什么需要它们?
\n\n服务器发送事件是HTML5标准,允许服务器通过单个HTTP连接实时向客户端发送数据。与WebSocket不同,SSE是单向的:只有服务器发送消息。但这正是它的优势所在——它极其简单,不需要额外的库。
\n\n何时选择SSE?
\n\n- \n
- 单向流式传输:通知、日志、汇率、股票行情。 \n
- 简单集成:通过浏览器中的标准
EventSource工作——无需npm包。 \n - 自动重新连接:浏览器在连接断开时自动恢复连接。 \n
- 与HTTP/2兼容:多路复用不会造成干扰,与WebSocket不同。 \n
但请记住:SSE无法从客户端向服务器发送数据(为此请使用常规POST请求),并且不支持旧版浏览器(IE——你好)。
\n\n服务器端:用TypeScript + Express编写SSE
\n\n我们从后端开始。创建一个基于Node.js、Express和TypeScript的简单服务器。安装依赖项:
\n\nnpm init -y\nnpm install express cors\nnpm install -D typescript @types/express @types/node ts-node\nnpx tsc --init\n\n现在编写服务器本身。关键点是设置正确的标头和消息格式。
\n\n// server.ts\nimport express, { Request, Response } from 'express';\nimport cors from 'cors';\n\nconst app = express();\napp.use(cors());\n\n// SSE端点\napp.get('/events', (req: Request, res: Response) => {\n // 设置SSE标头\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n });\n\n // 发送初始消息\n res.write('data: {"message": "连接已建立"}\\n\\n');\n\n // 每3秒发送一个事件\n const intervalId = setInterval(() => {\n const data = JSON.stringify({\n time: new Date().toISOString(),\n value: Math.random() * 100,\n });\n res.write(`data: ${data}\\n\\n`);\n }, 3000);\n\n // 处理客户端断开连接\n req.on('close', () => {\n clearInterval(intervalId);\n res.end();\n console.log('客户端已断开连接');\n });\n});\n\nconst PORT = 3000;\napp.listen(PORT, () => console.log(`SSE服务器已在端口${PORT}上启动`));\n\n请注意格式:每条消息以data:开头,以两个换行符\\n\\n结束。还可以指定id、event和retry——但这是基础。
发送命名事件
\n\n有时需要区分消息类型。添加event字段:
res.write('event: update\\n');\nres.write(`data: ${JSON.stringify({ id: 1, title: '新帖子' })}\\n\\n`);\n\n// 然后——另一个事件\nres.write('event: notification\\n');\nres.write('data: {"level": "info", "text": "服务器正在运行"}\\n\\n');\n\n在客户端,我们可以订阅特定事件。
\n\n客户端部分:在TypeScript中接收事件
\n\n现在编写客户端。在浏览器中,使用内置的EventSource。但如果