server-sent 事件 (SSE) 实现在线聊天

阅读时长 9 分钟读完

介绍

Server-Sent 事件 (SSE) 是一种用于在浏览器和服务器之间进行实时通信的技术。与 WebSockets 不同的是,SSE 建立在 HTTP 协议基础上,而不需要建立全双工的连接。SSE 可以用于实现类似在线聊天等实时通信的功能,具有轻量级、易用等特点。

在本文中,我们将介绍如何使用 SSE 实现一个简单的在线聊天应用。

实现原理

SSE 的原理很简单:浏览器通过向服务器发送一个 HTTP 请求,请求建立一个 SSE 连接。服务器接收到该请求后,将连接保持打开,并不断向浏览器发送事件消息。浏览器通过监听 EventSource 对象的 onmessage 事件,即可接收到事件消息,并进行相应的处理。

下面是一组示例代码,演示了如何在服务器使用 Node.js 和 Express 框架实现 SSE。

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

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

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

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

-- --- ---- ------
----------------
展开代码

上述代码实现了一个路由,用于处理客户端的 /chat 请求。该路由在响应头中设置了一些 SSE 相关的元信息,告诉浏览器这是一个 SSE 连接;然后使用 setInterval 定时向客户端发送一条消息,消息内容为当前时间戳。这个例子相当简单,只是为了演示 SSE 的基本实现原理。实际应用中,消息的内容和来源可能要复杂得多。

下面是客户端代码,使用了 EventSource 对象从服务器接收 SSE 消息。

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

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

-- ------
--------------------------------------- --------------- -
  -- ------
  -----------------------
--
展开代码

这段代码简单明了,只需要在 EventSource 构造函数中传入 SSE 连接的 URL,然后监听 message 事件,即可接收到服务器发送的消息。在生产环境中,建议使用 WebSocket 等专业的实时通信技术代替 SSE。

实践应用

下面我们来使用 SSE 实现一个在线聊天应用。在线聊天应用的实现方式很多,本文只介绍一种基于 SSE 的实现。该实现方式支持多个用户同时聊天,用户之间的聊天消息是实时同步的。

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

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

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

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

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

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

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

    -- -----
    ------------------------------------ ---------- -
      ----- ------- - -
        ----- ---------
        -------- ----------------
      -
      -------------- -
        ------- -------
        -------- -
          --------------- ------------------
        --
        ----- -----------------------
      --
      ---------------- - --
    --
  ---------
-------
-------
展开代码
-- -------------------- ---- -------
-- ---------

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

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

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

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

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

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

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

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

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

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

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

-- -------------
--- --------------- - --
展开代码

在服务器端,我们维护了两个队列: chatMessagesconnectionQueuechatMessages 保存所有聊天消息,当有新的消息时,将消息广播给所有处于连接状态的客户端;connectionQueue 保存所有的连接对象,当一个连接断开时,将该连接从队列中删除。

注意:由于 SSE 的连接是长连接,而且当前实现方式只支持单进程单线程模型。如果同时有大量的客户端连接,可能会导致服务器的资源崩溃。在生产环境中,我们需要使用专业的实时通信服务器,比如 Socket.IOPusher 等。

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

纠错
反馈

纠错反馈