详解Spring 5 Server-Sent Events(一) 基本介绍
SSE,全称Server-Sent Events,作为一种半双工的前后端通信方式,由于实现方式简单、轻量,在后端向前端的主动推送场景中具备很好的应用效果,笔者最近在一个项目中多有使用,过程中也是查阅了不少资料和文档,也有所感悟,在此将整体做一次综述。这是一篇系列文章,共分三篇,这是第一篇。
- 详解Spring 5 Server-Sent Events(一) 基本介绍
- 详解Spring 5 Server-Sent Events(二) WebMVC
- 详解Spring 5 Server-Sent Events(三) WebFlux
引言
在性能可接受的web应用程序中,没有简单、通用的方法来实现服务端到客户端的异步通信。
HTTP是B/S中的一种请求-响应协议。客户端(通常是浏览器)向服务端提交请求,服务端向客户端返回一个响应。服务端只能向发出请求的客户端发送响应。在HTTP协议中,客户端是消息交换的发起者。
在某些情况下,需要服务端成为消息交换的发起方。实现这一点的方法之一是允许服务端将消息推送到支持发布/订阅模式的客户端中。客户端从服务端订阅消息,服务端向许多订阅的客户端发送消息(一旦消息可用)。要停止交换,客户端需要取消订阅。
SSE(服务器发送事件)就是一种实现上述场景的技术。
概述
有几种技术允许客户端从服务端接收有关异步更新的消息。它们可以分为两类:客户端拉取和服务端推送。
客户端拉取
在客户端拉取技术中,客户端通过短轮询或者长轮询定期请求服务器进行更新。
短轮询
客户端定期向服务端发送请求。如果服务端有更新,它会向客户端发送响应并关闭连接。如果服务端没有更新,它会向客户端发送一个特殊响应,并关闭连接。
长轮询
客户端向服务端发送请求。如果服务端有更新,它会向客户端发送响应并关闭连接。如果服务端没有更新,它会保持连接,直到更新可用为止。当更新可用时,服务端向客户端发送响应并关闭连接。如果更新在一段时间内不可用,服务端将向客户端发送一个特殊响应,并关闭连接。
服务端推送
在服务端推送技术中,服务端在消息可用后立即主动地向客户端发送消息。其中,有两种类型的服务端推送:SSE和WebSocket。
SSE
SSE是一种仅发送文本消息的技术。SSE基于HTTP协议中的持久连接。SSE是HTML5标准协议中的一部分。
WebSocket
WebSocket是一种在web应用中实现同步、双向、实时通信的技术。WebSocket基于HTTP以外的协议(ws协议),因此它可能需要额外的网络基础设施设置(代理服务器、NAT、防火墙等)。然而,WebSocket可以提供使用基于HTTP的技术难以实现的性能。
SSE网络协议
去订阅一个服务端推送事件,客户端需要发起一个GET
请求,并设置如下的请求头:
Accept: text/event-stream
指明MediaType是事件流Cache-Control: no-cache
不要对事件进行缓存Connection: keep-alive
长连接
GET /sse |
服务端需要提供包含以下响应头的response
:
Content-Type: text/event-stream;charset=UTF-8
告诉客户端响应是一个事件流Transfer-Encoding: chunked
告诉客户端内容大小未知,为流传输
200 |
建立连接之后,服务端会在消息可用时立即发送消息。事件是UTF-8编码的文本消息。事件与事件之间由两个换行符分隔\n \n
。每个事件由一个或多个name:value
字段组成,用一个换行符分隔\n
。数据主要在data
字段中传输,一个标准的事件格式如下:
id:1 |
在一次事件消息发送过程中,可以有多个data行,比如:
data:第一个事件的第一部分信息 |
id
event
data
是比较常见的字段,除此之外,还常用到的是retry
字段。在retry
字段中,服务端告知客户端超时重连的时间间隔(单位是毫秒)。如果连接断开,浏览器会在达到超时时间后重新连接。如果未指定此字段,默认超时重连的时间是3秒。
另外一个常见的字段是:value
,即只有value
没有name
。它可以用来服务端向客户端发送注释,也可以用来保持连接,以防长连接超时断开。
: heartbeat |
SSE客户端处理
为了建立一个SSE
连接,客户端应该创建一个EventSource
对象。
var eventSource = new EventSource('/sse'); |
也可以在建立连接时传递参数给服务端。
var eventSource = new EventSource('/sse?event=type1'); |
关闭一个SSE
连接
eventSource.close(); |
连接有三种状态:
EventSource.CONNECTING = 0
正在连接EventSource.OPEN = 1
连接已建立EventSource.CLOSED = 2
连接已关闭
eventSource
的常用事件有以下几种:
//连接建立事件 |
对于消息的处理,一般会通过增加事件监听来进行。可以针对不同的event.type
设置不同的处理逻辑。
eventSource.addEventListener('DELETE_SONG', function (event) { |
EventSource
对象已经被绝大部分现代浏览器支持,具体支持的浏览器,可以翻阅Can I Use网站。