SSE (Server-Send Events) 服务端实时推送技术

在 HTTP 协议中,服务器无法向浏览器推送信息,可以使用 WebSocket 来实现两者双向通信。而SSE(Server-Sent Events),在浏览器向服务器请求后,服务器每隔一段时间向客户端发送流数据(是单向的),来实现接收服务器的数据,例如在线视频播放。

一、SSE 是什么

SSE(Server-Sent Events)是一种基于 HTTP 协议的推送技术。服务端可以使用 SSE 来向客户端推送数据,但客户端不能通过SSE向服务端发送数据。

二、应用场景

  1. 实时通知:在很多情况下,用户期望实时接收到应用的通知,如新消息提醒、商品活动提醒等。
  2. 节省资源:如果没有服务端推送,客户端需要通过轮询的方式来获取新信息,会造成客户端、服务端的资源损耗。通过服务端推送,客户端只需要在收到通知时做出响应,大大减少了资源的消耗。
  3. 增强用户体验:通过服务端推送,应用可以针对特定用户或用户群发送有针对性的内容,如优惠活动、个性化推荐等。
  4. chatGPT

三、与websocket 区别

SSE websocket
通信 单向通信 双向通信
协议 HTTP websocket
自动重连 支持 不支持,需要客户端自行支持
数据格式 文本格式,需要二进制数据需要二外编码 默认二进制数据、支持文本
浏览器支持 大部分主流现代浏览器 大部分主流现代浏览器
优势:
  • 简单易用:基于标准的HTTP协议,易于实现和调试。
  • 轻量级:不需要复杂的协议支持,如WebSocket。
  • 高效的网络利用:相比轮询,SSE减少了网络流量和延迟。
局限性
  • 单向通信:仅支持从服务器到客户端的数据流。
  • 浏览器支持:尽管大多数现代浏览器都支持SSE,但存在兼容性问题,尤其是在旧版浏览器中。
  • 缺乏控制:相比WebSocket,SSE提供的控制较少,例如无法控制连接的关闭。

四、数据格式

事件流是一个简单的文本流,仅支持 UTF-8 格式的编码。每条消息以一个空行作为分隔符。

在规范中为消息定义了 4 个字段:

event 消息的事件类型。客户端收到消息时,会在当前的 EventSource 对象上触发一个事件,这个事件的名称就是这个字段的值,如果消息没有这个字段,客户端的 EventSource 对象就会触发默认的 message 事件。

id 这条消息的 ID。客户端接收到消息后,会把这个 ID 作为内部属性 Last-Event-ID,在断开重连 成功后,会把 Last-Event-ID 发送给服务器。

data 消息的数据字段。客户端会把这个字段解析为字符串,如果一条消息有多个 data 字段,客户端会自动用换行符 连接成一个字符串。

retry 指定客户端重连的时间。只接受整数,单位是毫秒。如果这个值不是整数则会被自动忽略。

服务端

1.服务器首先向客户端声明接下来发送的是事件流( text/event-stream )类型的数据,然后就可以向客户端多次发送消息。

服务器端发送的数据的HTTP头信息如下:

css 复制代码
  res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
      'Access-Control-Allow-Origin': '*'
    })

数据格式

makefile 复制代码
field: value\n

field可以取四个值:"data", "event", "id", or "retry",也就是说有四类头信息。每次HTTP通信可以包含这四类头信息中的一类或多类。\n代表换行符。

以冒号开头的行,表示注释。 通常,服务器每隔一段时间就会向浏览器发送一个注释,保持连接不中断。

kotlin 复制代码
: this is a test stream\n\n
 
data: some text\n\n
 
data: another message\n
data: with two lines \n\n

data:数据栏

kotlin 复制代码
data: begin message\n
data: continue message\n\n

最后一行的data,结尾要用两个换行符号 \n\n,表示数据结束。

EventSource

EventSource 是服务器推送的一个网络事件接口。一个EventSource实例会对HTTP服务开启一个持久化的连接,以text/event-stream 格式发送事件, 会一直保持开启直到被要求关闭。

五、具体实践

服务端实现,基于node
javascript 复制代码
const http = require('http');
const server = http.createServer((req, res) => {
  console.log('req',req.url)
  let fileName = '.' +req.url
  if(fileName === './sse') {
    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
      'Access-Control-Allow-Origin': '*'
    })
    res.write('retry: 10000\n')
    res.write('event: connecttime\n')
    let interval = setInterval(() => {
      res.write(`data: ${new Date().toLocaleTimeString()}\n\n`);
    },1000)

    // 自定义事件
    req.connection.addListener(
      'close',
      () => {
        clearInterval(interval);
      },
      false
    )
  }

})
server.listen(3000, () => {
  console.log('Server is running at http://localhost:3000');
});
客户端实现
xml 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Title</title>
  </head>
  <body>
    <div id="example"></div>
    <script >
      let source = new EventSource('http://localhost:3000/sse')
      let _div = document.getElementById('example')

      source.onopen = function (event){
        _div.innerHTML ='<p>开始连接...</p>'
      }
      source.onerror = function (event){
        _div.innerHTML ='<p>关闭连接...</p>'
      }

      source.onmessage = function (event) {
        _div.innerHTML += '<p>Ping: ' + event.data + '</p>'
      }
    </script>
  </body>
</html>
输出
相关推荐
这是个栗子1 小时前
【问题解决】npm包下载速度慢
前端·npm·node.js
Komorebi_99991 小时前
数组和对象的深拷贝和浅拷贝的方法
前端·web
weixin_584121431 小时前
vue3+ts+elementui-表格根据相同值合并
前端·javascript·elementui
吃手机用谁付的款2 小时前
HTML常见标签
前端·html
好好研究2 小时前
CSS样式中的布局、字体、响应式布局
前端·css
拉不动的猪3 小时前
前端小白之 CSS弹性布局基础使用规范案例讲解
前端·javascript·css
伍哥的传说3 小时前
React强大且灵活hooks库——ahooks入门实践之开发调试类hook(dev)详解
前端·javascript·react.js·ecmascript·hooks·react-hooks·ahooks
界面开发小八哥4 小时前
界面控件Kendo UI for Angular 2025 Q2新版亮点 - 增强跨设备的无缝体验
前端·ui·界面控件·kendo ui·angular.js
枷锁—sha5 小时前
从零掌握XML与DTD实体:原理、XXE漏洞攻防
xml·前端·网络·chrome·web安全·网络安全
F2E_Zhangmo5 小时前
基于cornerstone3D的dicom影像浏览器 第二章,初始化页面结构
前端·javascript·vue·cornerstone3d·cornerstonejs