Server-sent Events 如何实现对推送消息的持久化存储与查询

阅读时长 12 分钟读完

HTML5 中的 Server-sent Events(简称 SSE)是一种服务器推送技术,允许服务器向客户端推送实时数据。相比于传统的轮询或长轮询方式,SSE 可以通过单个 HTTP 连接实现实时数据推送,从而降低了网络带宽和服务器负载,并提高了用户体验。

SSE 的工作原理是,客户端向服务器发送一个 HTTP 请求,并在请求头中设置 Accept: text/event-stream,表示希望接收服务器推送的事件数据。服务器接收到请求后,会向客户端发送一条 text/event-stream 格式的响应数据,其中包含一个或多个事件。每个事件由一个事件名称和事件数据组成,以及可选的事件 ID 和重试时间信息。客户端通过监听 EventSource 对象的 onmessage 事件来处理收到的事件数据,如下所示:

客户端接收到的数据格式如下所示:

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

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

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

但是,在实际应用中,服务器推送的事件数据通常会包含一些关键信息,如消息内容、事件来源、时间戳等,并且这些信息需要被持久化存储和查询。比如,一个实时聊天应用需要将每条消息保存到数据库中,并支持根据不同条件进行查询和统计。在本文中,我们将介绍如何通过 SSE 技术实现对推送消息的持久化存储与查询。

数据库设计

在将推送消息持久化存储到数据库中之前,我们需要先设计好数据库表结构。假设我们的推送消息数据包含以下字段:

  • id:消息 ID,自增主键
  • event_name:事件名称,用于区分不同类型的事件
  • data:事件数据,一个 JSON 字符串
  • timestamp:事件时间戳,用于记录事件发生的时间
  • source_type:事件源类型,如消息来源的用户、设备等
  • source_id:事件源 ID,如用户 ID、设备 ID 等

表结构如下所示:

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

服务器实现

接下来,我们需要在服务器端实现对 SSE 推送消息的持久化存储。我们可以使用 Node.js 平台的 Express 框架来搭建一个简单的 SSE 服务器。

首先,我们需要在服务器端创建一个用于存储 SSE 连接的数组 connections,每个 SSE 连接都对应一个客户端,用一个 response 对象来保存每个连接的响应数据,用一个 timeout 对象来保存每个连接的超时计时器。当客户端成功建立 SSE 连接时,服务器将向 connections 数组中添加一个新的 SSE 连接元素,并在超时时间内没有收到客户端的心跳数据时将该连接从 connections 数组中删除。

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

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

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

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

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

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

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

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

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

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

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

接下来,我们需要在服务器端监听数据的变化,并使用 EventSource#send 方法向客户端推送新的事件数据。在推送数据前,我们需要将数据插入到数据库中,然后根据需求生成事件名称和事件数据。最后,将事件数据通过 SSE 连接的响应对象发送给客户端。

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

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

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

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

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

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

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

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

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

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

最后,我们可以在 SSE 服务器启动后通过某种方式对数据进行修改或添加。比如,我们可以模拟一个消息入口,接收来自用户的消息,然后将消息数据存储到数据库并推送给客户端。

客户端实现

在客户端,我们可以使用 EventSource 类来处理服务器推送的事件数据。但是,在 SSE 技术中,已经收到的事件数据不能被重复接收,所以我们需要记录每个事件的最后 ID,下一次连接时从该 ID 开始接收事件数据。

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

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

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

同时,客户端需要定期向服务器发送心跳数据,保持 SSE 连接不断开。

最后,我们需要在 SSE 连接建立时传递上一次接收事件的最后 ID,从而避免接收到旧的事件数据。

结论

通过 SSE 技术,我们可以实现对推送消息的持久化存储和查询,并通过 SSE 推送技术将实时更新的数据即时推送到客户端,提高用户体验。但是,在使用 SSE 技术时需要注意以下几点:

  • SSE 技术不支持低版本浏览器,需要使用现代浏览器或 Polyfill 库来实现兼容性;
  • SSE 技术很难处理大规模推送数据,需要对服务器进行调优和优化;
  • SSE 技术需要与服务器端集成,需要对服务器进行编程。

完整示例代码可以在以下代码仓库中找到:https://github.com/tommyheavenly7/node-sse-mysql-example

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

纠错
反馈