对于一个聊天室应用来说,实时消息推送是非常重要的。在前端技术中,有很多种方式实现实时消息推送,比如WebSocket、Long Polling、Server-Sent Events(SSE)等等。本文将介绍如何使用 SSE 实现聊天室实时消息推送。
SSE 概述
SSE 是浏览器和服务器之间单向、实时、持久的连接。与 WebSocket 不同的是,SSE 不支持双向通信,也不能像 WebSocket 那样发送大量的二进制数据。但是,SSE 具有以下特点:
- 支持广播,可将同一事件发送给多个客户端。
- SSE 是基于 HTTP/1.1 的,因此无需额外的协议升级,使用 Web 服务器与浏览器之间的普通 HTTP 连接即可。
- SSE 可以通过 HTTP 缓存机制进行缓存,从而可以减轻服务器的负担。
SSE 实现聊天室实时消息推送
在 Express.js 中使用 SSE 实现聊天室实时消息推送有以下几个步骤:
- 创建 SSE 路由
首先,我们需要创建一个 SSE 路由,用于处理客户端的请求。我们可以使用 res.write()
方法将事件源(EventSource)对象发送到客户端。以下是在 Express.js 中创建 SSE 路由的示例代码:
// javascriptcn.com 代码示例 const express = require('express'); const router = express.Router(); router.get('/chat', (req, res) => { res.set({ 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' }); res.flushHeaders(); const eventId = Date.now(); res.write(`event: chat-room-connected\ndata: {"eventId":${eventId}}\n\n`); // send SSE messages to client setInterval(() => { res.write(`event: new-message\ndata: {"eventId":${eventId},"message":"Hello, world!"}\n\n`); }, 5000); }); module.exports = router;
在代码中,我们首先设置响应头,将 Content-Type 设置为 text/event-stream
,告诉客户端我们返回的是 SSE 数据。然后,我们调用 res.flushHeaders()
方法,确保响应头已经发送到客户端。
然后,我们生成一个 eventId,用于确保每一个 SSE 事件都是唯一的。然后,我们通过 res.write()
方法发送一个 SSE 事件,事件名为 chat-room-connected
,数据为 eventId。
最后,我们通过 setInterval 定期向客户端发送 SSE 事件,事件名为 new-message
,数据为 eventId 和消息内容。
- 连接 SSE 路由
接下来,我们需要在客户端连接 SSE 路由,以接收服务器发送的 SSE 事件。以下是在客户端连接 SSE 路由的示例代码:
// javascriptcn.com 代码示例 const eventSource = new EventSource('/chat'); eventSource.addEventListener('chat-room-connected', (event) => { console.log('Connected', event.data); }); eventSource.addEventListener('new-message', (event) => { const message = JSON.parse(event.data); console.log(message.message); });
在客户端代码中,我们使用 EventSource
构造函数创建一个事件源(EventSource)对象,并连接到 /chat
SSE 路由。然后,我们通过事件监听器监听服务器发送的 SSE 事件。
总结
SSE 是一种可靠的实时消息推送技术,可以用于实现聊天室中的实时消息推送。在 Express.js 中使用 SSE 实现聊天室实时消息推送的过程中,我们需要创建 SSE 路由和连接 SSE 路由。本文提供了详细的示例代码和指导,希望能对读者有所帮助。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/652e51947d4982a6ebf5c36c