十年前,若需开发实时应用(如聊天或更新feed),首选方案是轮询(polling)。此技术通过定时、重复发送HTTP请求到服务器获取更新数据。然而,即使没有新信息,请求仍会发送,造成带宽和服务器处理能力浪费。
所幸,时代变迁。如今使用JavaScript,我们可以借助EventSource库建立SSE(服务器发送事件)连接。本文将探讨SSE概念,并提供简要教程。
不同于传统HTTP请求(客户端发出请求,服务器返回响应),SSE连接始终保持打开状态,实现服务器到客户端的单向通信。与允许双向通信的WebSocket不同,SSE仅服务器向客户端发送数据,客户端在连接期间实时接收。
连接建立后,数据以事件形式到达JavaScript客户端,无需像轮询那样不断向服务器请求更新。服务器负责在必要时发送包含更新数据的事件。
除非连接关闭,客户端将持续等待服务器发送的新数据事件,这使其成为构建需要持续更新的通知、仪表盘或聊天的理想技术。
为了实践上述概念,我们将创建一个Node.js(后端)应用,提供SSE连接端点,供JavaScript客户端(前端)使用。
应用是一个系统,用户需输入UserID并建立SSE连接。之后,服务器每5秒发送一次事件,返回已连接用户列表。如果用户关闭连接,则会自动从已连接用户列表中移除。
让我们开始!
<code class="language-bash">npm init -y npm i express</code>
创建index.js文件,集中后端逻辑。此外,创建一个/public文件夹,存放index.html和script.js文件来管理页面。结构如下:
<code>/public index.html script.js index.js package.json</code>
在index.js中,导入express库(用于创建HTTP端点):
<code class="language-javascript">import express from "express" import fs from "fs" import path from "path" const app = express() app.use(express.json()) app.use(express.static(path.join(path.resolve(path.dirname("")), "public"))) app.get("/", (_, res) => { res.writeHead(200, { "content-language": "text/html" }) const streamIndexHtml = fs.createReadStream("index.html") streamIndexHtml.pipe(res) }) const PORT = 3000 app.listen(PORT, () => console.log(`Server is running on ${PORT} port`))</code>
在/public/index.html中,创建一个基本的HTML,显示标题并测试服务器是否运行:
<code class="language-html"><!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Server Sent Events Demo</title> <h1>Server Sent Events Demo (SSE)</h1> </head> <body> </body> </html></code>
现在,在终端运行npm start,页面应该会在浏览器中显示:
回到后端,创建connection.js文件,管理用户与服务器的连接:
<code>/public index.html script.js index.js connection.js package.json</code>
在其中,导出Connection类,存储已连接用户映射,以及registerUser方法(注册新用户)和removeUser方法(从映射中移除用户):
<code class="language-bash">npm init -y npm i express</code>
由于Connection类隔离了连接管理逻辑,我们需要在服务器(index.js)中配置一个端点,以便客户端可以启动SSE通信,这些连接将由Connection类管理:
<code>/public index.html script.js index.js package.json</code>
这里有三个重点:
Content-Type: text/event-stream
头响应客户端。这允许客户端识别SSE通信并创建EventSource对象以建立连接。req.on("close", () => {})
事件监控关闭的连接,允许将断开连接的用户从连接映射中移除。后端已完成!现在可以关注前端了。
由于服务器已提供SSE连接端点,客户端需要请求此地址并等待接收发送的事件。
在index.html文件中,我们将创建:
<ul><ul>
标签,显示已连接用户列表,该列表将使用服务器发送的事件更新。<code class="language-javascript">import express from "express" import fs from "fs" import path from "path" const app = express() app.use(express.json()) app.use(express.static(path.join(path.resolve(path.dirname("")), "public"))) app.get("/", (_, res) => { res.writeHead(200, { "content-language": "text/html" }) const streamIndexHtml = fs.createReadStream("index.html") streamIndexHtml.pipe(res) }) const PORT = 3000 app.listen(PORT, () => console.log(`Server is running on ${PORT} port`))</code>
然后在script.js中添加JS代码:
<code class="language-html"><!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Server Sent Events Demo</title> <h1>Server Sent Events Demo (SSE)</h1> </head> <body> </body> </html></code>
在浏览器中打开两个标签页测试实时连接,观察已连接用户的更新。
这样就完成了一个简单的SSE实时连接系统。此技术非常适合服务器需要持续向客户端发送单向数据的场景,例如feed、聊天或仪表盘。
请注意,为了完整性,我补充了错误处理和一些代码细节,例如在closeConnection
函数中添加了eventSource
的检查以及在startConnection
函数中添加了onerror
事件处理程序。 这些改进增强了代码的健壮性和可靠性。
以上是使用SSE(服务器式事件)创建实时应用程序的详细内容。更多信息请关注PHP中文网其他相关文章!