EventSource:Server-Sent Events协议学习笔记
Author:zhoulujun Date:
SSE 是一种仅使用 HTTP就可以实现客户端跟服务端建立单向长连接,从而实现服务端向客户端发送通知的目的 HTML5 标准。所以服务端基本不需要有啥变化。只需要按照特定的格式返回http请求即可!
SSE 协议
本质上是一个客户端发起的 HTTP Get 请求,服务器在接到该请求后,返回 200 OK 状态,同时附带以下 Headers
Content-Type: text/event-stream,SSE 的 MIME Type 规定为 text/event-stream
Cache-Control: no-cache,SSE 肯定不允许缓存
Connection: keep-alive,SSE 是一个一直打开的 TCP 连接,所以 Connection 为 Keep-Alive
之后,服务器保持连接,在 Body 中持续发送文本流,以实现实时消息推送。
由于是常规http GET请求,所以url传参数、基于cookie的身份认证都没有变化,只是需要发送Accept: text/event-stream来告诉服务端这是一个eventsource请求,服务端则要返回Content-Type: text/event-stream来确认对SSE的支持。
基础格式
文本流基础格式如下,以行为单位的,以冒号分割 Field 和 Value,每行结尾为 \n,每行会Trim掉前后空字符,因此 \r\n 也可以。
field: value\n
注释以冒号打头,格式如下
: This is a comment\n
为了连接保活,服务端可以每隔一段时间给服务端发一个注释,比如:idle
内容都推荐以utf8编码
id:事件唯一标示(可选)
每一个事件可以指定 ID,可以用于标记每个通知消息,这样在建立连接时,客户端可以把上次断开时最后拿到的id发给服务端,以此来获取连续的通知。
id: msg1\n data: message\n\n
浏览器会一直跟踪最近的事件ID,如果发生了重连,浏览器会把最近接收到的事件ID放入 HTTP Header “Last-Event-ID” 中,作为一种简单的同步机制。
event:事件(可选)
事件之间用 额外的\n 隔断, 每个事件既可以为单行,也可为多行。
下面所示是两个由单行组成的事件
data: message\n\n data: message2\n\n
而这一个是由多行组成的一个事件,更加易读
data: {\n data: "foo": "bar",\n data: "baz", 555\n data: }\n\n
命名事件
除了 ID 唯一标示一个事件之外,也可以通过命名的方式,区分一组类型的事件。默认情况下,事件会被命名为 “message”。
event: foo\n data: a foo event\n\n data: an unnamed event\n\n data: a bar event\n event: bar\n\n
上面的例子实际上是三个事件,第一个事件命名为 “foo”,第二个事件没有命名,第三个事件命名为”bar”。可以看出,在一个事件内部,”event” 可以放在前面,也可以放在末尾。
建议命名事件:这便于浏览器的addEventListener()可以只监听自己所以感兴趣的消息类型。
retry:重连时间(可选)
毫秒数,告诉客户端当连接断开后,等待多久再重新连接。
一般情况下,连接中断的时候,客户端会在 3 秒内进行重连,这个时间也可以由服务器来指定
retry: 10000\n
SSE保活
在使用 EventSource 的时候,与标准的HTTP请求,有两个关键的不同点:
服务器保持请求开启,而不是在发送完一个完整的响应后立即关闭连接。
响应头 Content-Type 被设置为 text/event-stream,告诉客户端数据是以服务器发送事件的格式收到的。
为了保持连接,EventSource 遵循几个步骤:
自动重连:如果连接因为任何原因中断,EventSource 客户端会尝试自动重连到服务器。它会等待一段时间(通常是几秒钟),然后尝试再次发起连接。
心跳消息:服务器可以定期发送注释行(以一个冒号 “:” 开头的行)作为心跳,即使没有实际的数据要发送。这样做可以防止某些网络基础设施(如代理或负载均衡器)因为超时而关闭看起来空闲的连接。
自定义重连时间:服务器可以在发送的消息中包含一个 retry 字段来告知客户端在尝试重连前应等待的时间。
最后事件ID:如果连接断开,客户端会发送一个特殊的 HTTP 头 Last-Event-ID,包含上次接收到的事件的ID。这样服务器可以从断点继续发送事件,保证没有事件丢失。
所有这些机制共同工作,帮助 EventSource 连接保持活跃并且在可能的情况下自动恢复。然而,开发者需要在服务器端实现适当的逻辑来支持这些机制,特别是定时发送心跳消息以及正确处理 Last-Event-ID 头的逻辑。
SSE工程实践
检测SSE支持
一般可以通过检测 EventSource 对象是否存在来判定当前浏览器是否支持 SSE
function supportsSSE() { return !!window.EventSource; }
EventSource
属性 | 说明 |
---|---|
EventSource.onerror | 当发生错误时被调用,并且在此对象上派发 error 事件 |
EventSource.onmessage | 服务器端发送给客户端一条消息时触发 |
EventSource.onopen | SSE 连接刚打开时触发 |
EventSource.readyState | 表示连接状态(CONNECTING 、OPEN 和 CLOSED) |
EventSource.url | 代表源头的 URL |
SSE使用
浏览器的eventsource便是对这个技术的原生支持。使用上,
直接创建 EventSource 对象即可,创建完成后,浏览器会及时打开。下面是案例代码
var source =new EventSource(url); // 连接事件源 source.onopen = function(event) { // handle open event }; source.addEventListener("open", function(event) { // handle open event }, false); // 接收事件源 source.onmessage = function (event) { var data = event.data; var origin = event.origin; var lastEventId = event.lastEventId; // handle message }; source.addEventListener('message', function (event) { var data = event.data; var origin = event.origin; var lastEventId = event.lastEventId; // handle message }, false); // 错误处理 source.onerror = function(event) { // handle error event }; source.addEventListener("error", function(event) { // handle error event }, false); //主动断开连接 source.close();
其实看文档就够了:https://developer.mozilla.org/zh-CN/docs/Web/API/EventSource
连接状态查看
switch (source.readyState) { case EventSource.CONNECTING: // do something break; case EventSource.OPEN: // do something break; case EventSource.CLOSED: // do something break; default: // this never happens break; }
SSE应用情况
相较于 WebSocket 而言,Server-Sent Events (简称SSE)更少被人知晓,具体实践也较少。原因有两点:
WebSocket 比 SSE 更强大,Websocket 在客户端和服务器之间建立了双向的实时通信。而 SSE 只支持从服务器到客户端的单向实时通信。
WebSocket 在浏览器方面支持更广(详见下图),IE / Edge 几乎根本不支持 SSE
但是SSE简单易用,于只需要能向客户端传输异步服务器消息的 Web 应用程序,服务器发送的事件是一个优雅且简单的解决方案。
业界中有许多知名的应用案例,特别是在需要实时或近实时信息更新的场景中。
Facebook 和 Twitter 等社交媒体平台可能会使用类似于SSE的技术来推送通知和更新给用户,比如用户的时间线更新或者是新的消息通知。
开发和运维工具如Grafana,可以利用SSE来实时更新仪表盘,显示系统的实时运行状态和性能指标。
参考文章:
SSE(server-sent events)的原理 https://www.hustyx.com/cpp/371/
转载本站文章《EventSource:Server-Sent Events协议学习笔记》,
请注明出处:https://www.zhoulujun.cn/html/theory/ComputerScienceTechnology/network/2024_0126_9033.html