探索SSE:实时Web通信的学习之旅

几种web实时通信机制
轮询
Websocket
Server-Sent Events
轮询
顾名思义,轮询就是在某个时间间隔内定期向服务器发送请求。其中轮询有分为短轮询和长轮询。这是一种客户端主动请求的方式。
短轮询
定期向服务器请求,无论请求的资源是否可用,服务器都会尽快响应,客户端再次发起下次轮询。这种方式会比较消耗网络带宽,如果资源一直不可用就会有很多不必要的请求发送到服务器。

长轮询
定期向服务器发送请求,与短轮询不同的是,在资源不可用时长轮询不会立即将连接关闭,而是会等待资源可用后在响应客户端。或者等待了一段时间资源任然不可用(超时)服务器将连接关闭,客户端等待一段时间后再次发起请求。

与短轮询相比,长轮询更高效一些,请求数量减少了很多。
Websocket
在客户端和服务器打开交互式的通信会话。这是一种全双工通信,客户端与服务器会建立一个持久连接,服务器可以主动发送数据给客户端。客户端可以通过监听事件来处理来自服务器的消息。与轮询的方式相比,大大减少了延迟,没有了数据更新的往返时间。

Server-Sent Events
服务器发送事件,SSE会建立一个持久的HTTP连接。建立连接后服务器可以主动往客户端推送数据。与websocket不同,这是一种单向通信的方式,即建立连接后客户端不能向服务器发送数据。

通常来说,一个网页获取新的数据通常需要发送一个请求到服务器,也就是向服务器请求的页面。使用服务器发送事件,服务器可以随时向我们的 Web 页面推送数据和信息。这些被推送进来的信息可以在这个页面上以 事件 + 数据 的形式来处理。
事件流是一个简单的文本数据流,文本应该用UTF8格式编码。事件流的消息由两个换行符分开,以冒号开头的行为注释行,会被忽略。

事件流字段
用于标识事件类型的字符串,如果没有指定event,浏览器默认认为是message。
消息的数据字段,当EventSource收到多个已```data:```开头的连续行是,会将它们连接起来,在它们之间插入一个换行符。,末尾的换行符也会被删除。
事件ID,会被设置为当前EventSource对象的内部属性“最后一个事件ID”的值。
重新连接的时间。如果与服务器的连接丢失,浏览器会等待指定的时间,然后重新连接。retry必须是一个整数,它的单位是毫秒。
使用
SSE的用法比较简单,只需要在服务器编写一些代码将事件流传输到前端。前端使用EventSource来监听这些事件流。



代码放在https://github.com/raojinlin/server-sent-events-demo/tree/main,有兴趣的通信可以看看。
注意事项
nginx配置
使用nginx做反向代理时需要将proxy_buffering关闭
proxy_buffering off
或者加上响应头部x-accel-buffering,这样nginx就不会给后端响应数据加buffer
x-accel-buffering: no
EventSource
连接关闭后会自动重连
需要显示的调用close方法
EventSource.prototype.close
参考
https://developer.mozilla.org/zh-CN/docs/Web/API/Server-sent_events/Using_server-sent_events