使用 Server-Sent Events 在 Node.js 和 Koa 2 中进行全双工通信

阅读时长 8 分钟读完

在现代的 Web 应用中,实时信息推送已经成为了必要的功能之一,其中最常用的技术是 WebSocket。但在某些情况下,我们可能不需要完整的 WebSocket 功能,而只需要单向或双向的实时数据传输。这时候,可以使用 Server-Sent Events(简称 SSE)来实现。

SSE 是一种只读的 HTTP 流技术,它允许服务器实时地向客户端发送事件。由于 SSE 基于 HTTP,因此不需要额外的协议或端口,可以和现有的 Web 技术完美集成。同时,它还具有 WebSocket 不具备的优势,如自动重连、浏览器兼容性良好等。

本文将介绍如何在 Node.js 和 Koa 2 中使用 SSE 实现全双工通信。

基本使用

SSE 的核心是 EventSource 对象,它是浏览器内置的 API,可以订阅服务器发送的事件。以下是一个最简单的 SSE 示例:

在这个例子中,我们创建了一个 EventSource 对象并指定了一个 URL。浏览器会通过这个 URL 建立一个 HTTP 连接,并在连接上监听服务器发送的事件。当服务器有数据到达时,浏览器会触发 message 事件,并将数据传递给事件回调函数。

我们只需要在服务器端实现一个 SSE 接口,该接口应该使用 text/event-stream 格式向客户端发送事件。每个事件都包含一个事件类型和数据字段,如下所示:

在 Node.js 中,可以使用类似下面的代码实现 SSE 接口:

-- -------------------- ---- -------
----- ---- - ---------------

----- ------ - ----------------------- ---- -- -
  -- -------- --- ---------- -
    ----------------------------- --------------------
    ------------------------------ -----------
    --------------------------- -------------

    -------------- -- -
      ----------------- -----------
      ---------------- ----- ---------------------------
    -- -----
  - ---- -
    -------------- - ---
    ---------
  -
--

-------------------

在这个例子中,我们创建了一个 HTTP 服务器,并在 /stream 接口上实现了 SSE。我们通过设置响应头的方式告诉浏览器,该响应使用 text/event-stream 格式,并且需要保持持久连接(即 Connection 头部设置为 keep-alive)。

在 SSE 中,每个事件可以包含一个可选的事件名称(即 event 字段),可以用来过滤事件类型。在这个例子中,我们将事件名称设置为 message,并在事件数据中返回了当时的时间戳。客户端将会每秒收到一个名为 message 的事件,并显示当前时间。

Koa 2 中的实现

现在我们来看看如何在 Koa 2 中使用 SSE 实现全双工通信。首先,我们需要封装一个 SSE 中间件,用来处理 SSE 请求和响应。

-- -------------------- ---- -------
-------- ------------- -- -
  ------ ----- ----- ----- -- -
    ---------
      --------------- --------------------
      ---------------- -----------
      ------------- ------------
    --

    -------- - --- ----------
      ---- -- --
    --

    ----- ------ - --------
    ----- -- - ----------

    -- -------
    ---------------- -----------

    -- -------
    ----- --------- - --- -----
    ----- -------- - ------- ----- -- -
      ----- ------- - ---------------- -----
      --- ------ ------ -- ----------------- -
        ---------------------
      -
    -
    ------- - -
      ---- ------- ----- -
        --------------- -----
      --
      -- ------- --------- -
        ---------------------------------- ------- ----------
      --
      --- -- -
        -------------------------------------
      -
    -
    --------------------------------------- ---------

    -- ------------
    --------------------- -- -- -
      ------------------------------------------ ---------
      -------------------------------------
    --

    ----- ------

    -- ---- ------
    -----------------
  -
-

-------- --------- ------- ----- -
  ----- ------ - --
  -- ------- ------------------- ----------
  -- ----- --- ---------- ------------------ -------------------------
  ------ ----------------- - ------
-

在这个中间件中,我们创建了一个 Readable 流,用来产生 SSE 数据,并将其赋值给 ctx.body。在 SSE 中,每个事件都必须以一个 ID 字段开始,该字段可以用来过滤重复数据。我们使用当前时间戳作为 ID,并将其初始化发送给客户端。

接下来,我们定义了一些 SSE 相关的方法。send 方法用于向客户端发送事件,on 方法用于注册事件监听器,off 方法用于取消注册。我们使用一个全局的 EventTarget 对象来统一管理所有事件,这可以确保不同的 Koa 实例之间也可以互相通信。

在 onRequest 回调中,我们注册了一个 'close' 事件监听器,用来在请求结束时清理事件监听器和响应流。

现在,我们就可以在路由中使用这个 SSE 中间件了。

-- -------------------- ---- -------
----- --- - --- -----

------------- ----- ----- -- -
  -- --------- --- -------- -
    ----------------------- ------------
    -------- - -
      --------
        ----- ------ - --- --------------------
        --------------------------------- ----- -- -
          ----- ---- - ----------------------
          -------------------------
        --
      ---------
      -
  - ---- -
    ----- ------
  -
--

------------------------

------------- ----- ----- -- -
  -- --------- --- -------- -
    --------------------- ---- -- -
      ---------------------- --------- ------
    --
  - ---- -
    ----- ------
  -
--

----------------

在这个例子中,我们定义了一个 /chat 路由,用来展示 SSE 的使用。在页面上,我们创建了一个 EventSource 对象并订阅了 custom 事件,当服务器发送 custom 事件时,页面会显示事件的数据。

在 Koa 中,我们只需要使用 sseMiddleware 中间件即可创建 SSE 接口。在 before 中间件中,我们为 /chat 路由返回了一个 HTML 页面。在 SSE 中间件和 after 中间件中,我们注册了事件监听器和发送事件的代码。当客户端连接 SSE 接口后,它会收到名为 custom 的事件,并展示服务器发送的数据。

结论

通过本文的学习,我们了解了如何使用 Server-Sent Events 在 Node.js 和 Koa 2 中实现全双工通信。SSE 是一种轻量级的实时通信技术,具有自动重连、浏览器兼容性好等优点,在某些情况下可以替代 WebSocket。

在实际项目中,我们还需要考虑安全性、性能等问题,如如何限制客户端数量、如何保护数据安全等。与 SSE 相关的资源管理和事件管理,也需要根据具体的场景进行设计和实现。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6750fc14050cf9039c186bca

纠错
反馈