前言
SSE(Server-Sent Events)是 HTML5 中的一个新特性,提供了一种从服务器向客户端推送事件的 HTTP 通讯方式。相对于传统的轮询和长轮询方式,SSE 建立在单个 HTTP 连接上,可以大量减少不必要的网络开销和服务器负载。Nginx 是目前非常流行的反向代理和 Web 服务器,它具有高效稳定和可扩展性等优势。结合 SSE 和 Nginx 的使用,可以构建高性能的实时通讯系统。
本文将介绍如何使用 SSE 和 Nginx 搭建一个简单的实时聊天室应用,并探讨其中的技术原理和实现细节。
准备工作
在开始之前,需要先安装并配置好以下工具:
- Nginx:反向代理和 Web 服务器,用于接收和路由 SSE 请求。
- Node.js:服务器端 JavaScript 运行环境,用于实现应用的逻辑部分。
- Redis:内存数据库,用于保存和管理聊天室消息和在线用户。
实现过程
SSE 服务器
首先,我们需要一个 SSE 服务器,它将负责接收客户端的连接和推送实时事件。在 Node.js 中,可以使用 sse
模块来实现 SSE 服务器的功能,代码如下:
-- -------------------- ---- ------- ----- --- - --------------- ----- ---- - ---------------- ----- ------ - ----------------------- ---- -- - ------------------ - --------------- -------------------- ---------------- ----------- ------------- ------------ --- ----- --- - --- -------- ----- ---------- --- -- ----- ----------- --- --------------- -- -- - ------------------- --------------- --- --- ------------------- -- -- - ---------------- ------ ------- -- ---- ------- ---
在上述代码中,我们首先创建了一个 HTTP 服务器,将响应头的 Content-Type 设置为 text/event-stream,表示这是一个 SSE 服务器对客户端的响应。然后,我们创建了一个 sse
实例,将其与当前请求和响应对象关联起来。当客户端向服务器建立连接时,我们使用 sse.send()
方法向其推送一个“connected”事件。最后,我们监听了 sse
实例的 close
事件,在客户端连接断开时打印一条消息。
消息和用户管理
接下来,我们需要实现一个消息管理器,用于保存和管理聊天室中的历史消息和在线用户。在 Node.js 中,可以使用 Redis 数据库来存储这些信息。以下是消息管理器的实现:
-- -------------------- ---- ------- ----- ----- - ----------------- ----- ------ - --------------------- ----- ----------- - ----------- ----- -------- - --------------- -------- ------------------- - ----- --- - ------------------------ ------------------------- ---- ----- ---- -- - -- ----- ----- ---- -------------------- -------- --------- --- - -------- ------------------ --- - -------------------------- -- ----- - -- ----- ---- -- - -- ----- ----- ---- ----- -------- - --- -------- -- ---------------- ----------- ------------- --- - -------- ------------- - --------------------- ----- ----- ---- -- - -- ----- ----- ---- ----------------- -------- ------ --- - -------- ---------------- - --------------------- ----- ----- ---- -- - -- ----- ----- ---- ----------------- ---------- ------ --- - -------- ------------------ - ------------------------- ----- ---- -- - -- ----- ----- ---- -------- --- - -------------- - - ----------- ------------ -------- ----------- -------------- --
在这段代码中,我们创建了一个 Redis 客户端连接,并定义了五个函数,分别用于:
- 添加一条新消息到 Redis 中。
- 获取最近 count 条历史消息。
- 添加一个在线用户到 Redis 集合中。
- 从 Redis 集合中删除一个离线用户。
- 获取所有在线用户。
路由和控制器
接下来,我们需要实现服务器端的路由和控制器,用于处理客户端请求和控制 SSE 服务器的行为。在路由和控制器之间,我们可以使用 Express 框架来实现。以下是路由和控制器的实现:
-- -------------------- ---- ------- ----- ------- - ------------------- ----- --- - ---------- ----- ------- - --------------------- ----- --- - ----------------- ---------------------------------- -------------------- ----- ---- -- - ----- ----- - --------------- -- --- -------------------------- -------- -- - ------------------- --- --- ----------------- ----- ---- -- - ---------------------------- -- - ---------------- --- --- --------------------- --------------- ----- ---- -- - ----- - ----- ------- - - --------- ----- ---- - --- --------------------- ----- ---- - - ----- -------- ---- -- ---------- ---- --- ------------------------- ---------- --- -------------------------- ----- ---- -- - ----- - ---- - - ----------- ---------- ----- - ----- ------------ ----- ---- - --- ------------------------- ---------- --- ---------------- -- -- - ---------------- --------- -- ---- ------- ---
在上面的代码中,我们首先使用 Express 的 static()
方法将 public
目录作为静态文件目录服务出来。然后,我们定义了四个路由:
/messages
:获取最近的 count 条历史消息。/users
:获取当前所有在线用户。/messages
(POST):添加一条新的聊天消息。/users
(DELETE):删除一个用户,表示其下线。
我们将这些路由定义在 app
实例中,并将其监听在 4000 端口上。
在控制器中,我们调用了 Message
模块提供的各种函数来实现相应路由的功能。其中,在 /messages
路由的控制器中,我们不仅向 SSE 服务器发送了一个新的事件,同时也将其保存到 Redis 中。
Nginx 配置
最后,我们需要将 Nginx 配置成一个反向代理,将客户端请求路由到 SSE 服务器,并进行负载均衡和安全性控制。以下是 Nginx 的配置文件:
-- -------------------- ---- ------- ---------------- -- ------ - ------------------ ----- - ---- - -------- ----------- - ------ --------------- - ------ - ------ --- ----------- ---------- -------- - - ---------- ------------------- ---------------- ---------- ------------- ---------------- ------------- ----------- - - -
在上述配置文件中,我们首先定义了一个 upstream 块,其中指定 SSE 服务器的地址和端口。然后,我们定义了一个 server 块,将其监听在 80 端口上。在 location 块中,我们将所有请求路由到 sse_backend
这个 upstream 中,并设置了几个代理头。
客户端代码
最后,我们需要编写一个客户端代码,用于与该聊天室应用进行互动。以下是简单的 HTML 和 JavaScript 代码:
-- -------------------- ---- ------- --------- ----- ------ ------ ---------- ---------------- ----- ---------------- ------- ------ ------- ------------- ----- ------- ------------------------ ------- ------------------------- ------ ----- --- ------------------- ------ ----- ----- ---------- ------ ----------- --------- ----------------- --------- ------ ----------- ------------ ---------------- --------- ------- ------------------------- ------- ------ -------- ----- ---- - ------------------ ----- -------- - ------------------------------------ ----- ---- - -------------------------------- ----- ------- - -------------------------------- ----- -------- - --------------------------------- --- ------ - ----- --------------------------------- -- -- - ------ - --- ----------------------- ---------------------------------- - -- - ----- - ----- -------- ---- - - ------------------- ----- -- - ----------------------------- ------------ - -------- ---------- ------------ ------------------------- --- -------------------------------- - -- - ------------------------ -------- --- --- ----------------- - ------ ---------------- - ----- --- ---------------------------------- -- -- - --------------- ----------------- - ----- ---------------- - ------ --- ------------------------------- - -- - ------------------- ----- --------- - ----------------------------------- ----- ------- - ---------------- --------------- - --- ------------------ - ------- ------- -------- - --------------- ------------------ -- ----- ---------------- ----- ------- -- --- --- --------- ------- -------
在这段代码中,我们首先要求用户输入一个用户名,并对 DOM 元素进行了简单的选择和注册事件。当用户点击“加入聊天室”按钮时,我们使用 EventSource
API 向 /events
路径建立 SSE 连接,并监听 message
和 error
事件。当用户发送一条新消息时,我们使用 fetch
API 向 /messages
路径发送一个 POST 请求,并将消息内容和用户名打包在 JSON 格式的对象中。
总结
本文介绍了如何使用 SSE 和 Nginx 结合实现一个简单的实时聊天室应用。我们学习了如何在 Node.js 中使用 sse
模块实现 SSE 服务器、使用 Redis 实现消息和用户管理、使用 Express 实现路由和控制器、使用 Nginx 实现反向代理和负载均衡、以及使用 EventSource API 和 fetch API 实现客户端代码。在实现的过程中,我们遇到了很多技术难点,例如:兼容性问题、服务器推送和客户端接收、负载均衡和安全控制、数据持久化和管理等等。通过本文的学习和实践,读者可以掌握这些技术,并能够将它们应用到自己的项目中。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64c0bd3f83d39b4881516ee2