在 Web 应用中,经常需要实现实时更新页面内容的功能;例如:推送新闻、即时聊天、实时更新数据等等。传统的前端实现是通过 Ajax 轮询获取数据,但会造成服务器的资源浪费,同时用户也会感受到页面的延迟。而 Server-Sent Events(服务器发送事件)是一种轻量级的“推”机制,可以在服务器端节省资源的同时提供实时更新的服务。
什么是 Server-Sent Events
Server-Sent Events 是一种基于 HTTP 协议的即时通讯技术,它建立在简单的事件流协议上,允许 Web 服务器通过单向连接向客户端发送事件或数据。相较于 WebSocket,Server-Sent Events 无需进行握手,更加轻量化,适用于少量数据传输和实时事件通知。
Server-Sent Events 的通信过程如下:
- 客户端向服务器端发送 HTTP 请求,要求建立 Server-Sent Events(SSE)连接。
- 服务器端向客户端响应 SSE 连接请求,建立 SSE 连接,通过连接随时向客户端发送数据。
- 客户端通过事件监听器接收从服务器端发送的数据。
Server-Sent Events 的优势
相较于传统的 Ajax 轮询方式,Server-Sent Events 有以下优势:
- 减少服务器压力:使用 Server-Sent Events 可以通过单向连接响应客户端请求,省去了无用的响应数据,减少了服务器压力。
- 实时通知:使用 Server-Sent Events 可以实时向客户端发送数据,不需要等待客户端的请求,客户端可以在数据更新时直接进行页面更新。
- 更加节约带宽:使用 Server-Sent Events 可以减少废弃的请求,使得服务器只发送必要的数据,减少了带宽的消耗。
Server-Sent Events 的使用
Server-Sent Events 分为服务端和客户端两部分,下面是它们的具体实现方法。
服务器端
在 PHP 中,我们可以通过以下代码来实现 Server-Sent Events:
-- -------------------- ---- ------- --------------------- -------------------- ---------------------- ----------- ----- ------ - ----- - ----------- -- --------- ---- ------ ----------- -- ---- ----------- -------- --------- -- -------- - - -
其中,header("Content-Type: text/event-stream"); 表示返回数据类型为 Server-Sent Events,header("Cache-Control: no-cache"); 表示不缓存数据。
通过 while 循环,不断获取需要发送的数据,使用 echo 发送数据。每个 SSE 事件都需要一个唯一的事件类型,可以通过 event: 标识符来指定,也可以省略。
客户端
在客户端,我们需要创建一个 EventSource 对象,通过监听其 onmessage 事件来接收服务器发送的数据。以下是 JavaScript 中实现 SSE 的代码示例:
var source = new EventSource('sse.php');
source.addEventListener('message', function(event) {
console.log('Received:', event.data);
});new EventSource('sse.php') 表示创建一个 SSE 连接,通过传入的 URL 与服务器进行通信。
source.addEventListener('message') 则表示监听 SSE 的消息事件,当服务器端向客户端发送数据时,onmessage 事件便会被触发。
Server-Sent Events 的局限性
Server-Sent Events 拥有很多优点,但也存在以下局限性:
- 浏览器兼容性问题:部分浏览器不支持 SSE 的实现,需要使用 polyfill 进行兼容。
- 单向数据流:SSE 的通信是单向的,只支持由服务器向客户端发送数据,因此不适用于共享实时双向数据的场景。
- 连接维持:SSE 需要客户端和服务器维持一个长连接,如果连接断开必须重新建立连接。同时如果服务器应用崩溃或重启,客户端需要重新建立连接。
结语
Server-Sent Events 是一种轻量级、高效的即时通讯技术,能够提供实时更新页面内容的服务,同时还可以节省服务器资源。虽然它存在一些局限性,但在适用场景下,仍然是一种优秀的技术方案。
Source: FunTeaLearn,Please indicate the source for reprints https://funteas.com/post/67c69ea7cf1e9924e1eda32c