服务器消息推送SSE

# 背景

服务端向客户端(浏览器)消息推送常用的两种方式:

  • WebSocket 长链接
  • http 轮询

轮询 由客户端主动发起,那有没有一种服务端主动发起的呢?

html5 SSEServer-Send Events 满足了这样的需要

优点:

  • 断线重连
  • 自定义消息类型
  • 重复 http 协议,现有接口代码少量改动即可使用
  • 兼容性还不错,除了 IE,大胆用~

缺点:

  • 规定的传送数据字段只能为 data 且只可以传送文本

# 客户端(浏览器)实现

// 创建 sse 消息推送对象,监听服务端 sse 接口服务
const sse = new EventSource('http://127.0.0.1:8866/api/stream?q=sse')
// 打开连接
sse.addEventListener('open', (event) => {
  console.log('open')
}, false)

// 监听服务端默认 message 事件信息
sse.addEventListener('message', event => {
  console.log(event)
  console.log(event.data)
})

// 监听服务端 sse 事件信息
sse.addEventListener('sse', event => {
  console.log(event)
})

// 连接报错
sse.addEventListener('error', event => {
  console.log(event)
})

// 5s 后断开连接
setTimeout(() => {
  sse.close()
  // 释放 open、message、see、error 事件
}, 5 * 1000)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 服务器实现 (Nodejs)

// 主要代码逻辑
app.get('/api/stream', async (req, res) => {
  let timer = null
  // 消息块
  // 消息块用 \n\n 结尾 不加?data 消息连接另外一条消息
  // 消息块中单个字段用 \n 结尾 不加?此消息失效
  // \n 前最好不要加空格,保证输出结果中没有空格
  // event-stream 文本书写格式
  if (!req.query.q) {
    res.send('404')
    return false
  }
  res.write(`retry: 1000\n`)
  res.write(`id: ${+ new Date()}\n`)
  res.write(`data: ${JSON.stringify({
    eventName: 'message'
  })}\n\n`)



  timer = setInterval(() => {
    // 另外消息块
    // 自定义 sse 事件
    res.write(`retry: 1000\n`)
    res.write(`event: sse\n`)
    res.write(`id: ${+ new Date()}\n`)
    res.write(`data: ${JSON.stringify({
      eventName: 'sse'
    })}\n\n`)
  }, 1000)

  req.connection.addListener('close', () => {
    console.log('SSE 关闭: closed')
    clearInterval(timer)
    timer = null
  })
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

扫一扫,微信中打开

微信二维码