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