Appearance
EventSource
一种服务端主动向客户端推送消息的规范,一个EventSource
实例开启一个持久化的 HTTP 连接,发送Content-Type
为text/event-stream
的事件,直到要求关闭为止。
例如: 客户端主动调用 eventSource.close()
方法
注意: EventSource
和 WebSocket
不同,数据是单向的,只能从服务端往客户端推送数据。
所以当我们仅需要从服务器向客户端推送消息时,使用 EventSource
会更好。
Event stream 的格式
名称 | 含义 |
---|---|
event | 消息名称 |
data | 消息体 |
id | 当前消息标识符 |
retry | 重连间隔时间 |
这里需要注意的是:
event
后面需要跟一个\n
,而在data
后面需要跟两个\n
,表示当前消息体发送完毕,不用等待后面数据的到来再触发事件。id
字段基本上没有使用。使用冒号作为行的第一个字符代表着注释行,会被忽略,不过可以用于防止连接超时
event:${event}\ndata:${data}\n\n
Demo
客户端代码
javascript
// withCredentials:指示 CORS 是否应该包含凭据
const eventSource = new EventSource('http://localhost:3000/test', {
withCredentials: true,
});
// EventName 是服务端的 EventSource event 字段的值
eventSource.addEventListener('test', (event) => {
console.log(event.data);
});
服务端代码
javascript
const http = require('http');
const fs = require('fs');
const path = require('path');
const server = http.createServer((req, res) => {
// 由服务端发送 index.html,确保同源,避免要处理跨域的问题
// if (req.url === '/index' || req.url === '/index.html') {
// const file = fs.createReadStream(path.resolve(__dirname, '..', 'client') + '/index.html');
// res.writeHead(200, { 'Content-Type': 'text/html;charset=UTF-8' })
// file.pipe(res);
//}
// 推送 event-source 消息
if (req.url === '/test') {
// Content-Type 需要设置为 text/event-stream
res.writeHead(200, { 'Content-Type': 'text/event-stream' });
// event 字段后跟一个 \n,data 字段后跟两个 \n,这是必需的,代表着当前消息体发送完毕
const packet = 'event: test\ndata:{"message":"Test a Event Source"}\n\n';
res.write(packet);
res.end();
}
})
server.listen(3000);