Skip to content

EventSource

一种服务端主动向客户端推送消息的规范,一个EventSource实例开启一个持久化的 HTTP 连接,发送Content-Typetext/event-stream的事件,直到要求关闭为止。

例如: 客户端主动调用 eventSource.close() 方法

注意: EventSourceWebSocket 不同,数据是单向的,只能从服务端往客户端推送数据。

所以当我们仅需要从服务器向客户端推送消息时,使用 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);