SSE(server-sent events)的原理

SSE可以实现客户端跟服务端建立单向长连接,从而实现服务端向客户端发送通知的目的。它兼容常规http请求,所以服务端基本不需要有啥变化。其基本原理也非常简单,就是客户端向服务端发起一个GET请求,而服务端不返回Content-Length,按一定的格式在需要时返回一段结果,这样客户端一直处于解析结果的状态。看起来有点像http chunked编码,但显然不是一个东西。

浏览器的eventsource便是对这个技术的原生支持。考虑到浏览器对同域名建立连接的限制,如果打开多个tab,一个tab建立一个连接,那么开启超过6个tab,就会出问题,在http/1.1下,浏览器默认同域名最多建立6个连接。如果是http/2,这个默认值大概是100.

由于是常规http GET请求,所以url传参数、基于cookie的身份认证都没有变化,只是需要发送Accept: text/event-stream来告诉服务端这是一个eventsource请求,服务端则要返回Content-Type: text/event-stream来确认对SSE的支持。

eventsource定义了四种数据类型:

1. id

可以用于标记每个通知消息,这样在建立连接时,客户端可以把上次断开时最后拿到的id发给服务端,以此来获取连续的通知。可选。

2. event

消息的类型,这便于浏览器的addEventListener()可以只监听自己所以感兴趣的消息类型。可选。


event: userconnect
data: {"username": "bobby", "time": "02:33:48"}

event: usermessage
data: {"username": "bobby", "time": "02:34:11", "text": "Hi everyone."}

3. data

消息内容,以data:打头,如果有多条连续的data,浏览器会将他们用换行符拼接起来,作为一整个消息。至于消息内容,格式自定义。


data: some text

data: another message
data: with two lines

4. retry

毫秒数,告诉客户端当连接断开后,等待多久再重新连接。可选,一般在建立连接后,由服务端作为第一个通知发给客户端。


retry: 3000

此外,还有一些约定:

  • 所有内容都以utf8编码
  • 两条消息之间用换行符(\r\n)进行分隔
  • 以冒号(:)打头的行为注释,直接忽略掉
  • 为了连接保活,服务端可以每隔一段时间给服务端发一个注释,比如:idle

注意:SSE跟chunked编码类似,需要客户端提供边接收边解析的接口,但有些场景,比如微信小程序,它不提供专门的支持,而只支持chunked编码,此时就需要实现基于chunked传输编码的SSE了。

发表于 2022年01月02日 01:08   修改于 2022年01月03日 14:43   评论:0   阅读:4438  



回到顶部

首页 | 关于我 | 关于本站 | 站内留言 | rss
python logo   django logo   tornado logo