解决 Chrome 浏览器下 SSE 自动中断连接的问题

阅读时长 6 分钟读完

前言

SSE (Server-Sent Events) 是一种服务器向客户端推送事件的机制,它基于 HTTP 协议,但相比于长轮询和 Websocket,它具有更轻量的通信开销和更简单的协议实现。因此,它在 web 开发中得到了广泛的应用。

然而,如果你在使用 SSE 时遇到了 Chrome 浏览器自动断开 SSE 连接的问题,那么在本文中,我将详细介绍这个问题的原因和解决方法,并带给你实际代码的示例。

问题描述

在使用 SSE 时,我们通常会创建一个 EventSource 对象,然后通过 onmessage 事件监听 SSE 服务器发来的消息。

然而,在 Chrome 浏览器下,有时候这个连接会在没有与服务器主动断开的情况下自动中断,出现长时间没有数据推送的断开状态:

这是什么原因呢?如何解决呢?

问题原因

要解决这个问题,我们首先需要了解它的原因。在 Chrome 浏览器下,SSE 连接有时候会自动中断,通常是因为以下两个原因:

  1. 服务端发送的消息过长。在 Chrome 浏览器下,如果服务端发送的消息长度超过 16KB,那么就会触发自动中断 SSE 连接的机制,此时需要通过拆分消息来绕过这个限制。

  2. 超过 30 秒没有接收到数据。在 Chrome 浏览器下,如果 SSE 连接在 30 秒内没有接收到任何数据,那么就会自动中断,此时需要通过心跳机制来保持连接。

解决方法

拆分消息

对于第一个问题,我们可以通过拆分消息来绕过 16KB 的限制。通常,这个限制往往是由服务端所决定的,因此我们需要在服务端拆分消息并发送多个小段的消息,让客户端能够正确地处理这些消息。

以下是一个示例代码,它将一个长字符串拆分成多个小段并发送:

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

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

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

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

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

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

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

在客户端,我们需要对拆分后的多个小段消息进行合并,以得到最终的完整消息:

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

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

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

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

需要注意的是,我们在 server.js 文件中使用了 idevent 字段来标识 SSE 的消息类型和消息序号,并在客户端代码中使用 event.lastEventId 来判断当前是否已经接收到最后一个消息段。

心跳机制

对于第二个问题,我们可以通过心跳机制来保持连接活性。通常,我们可以在 SSE 连接的 onopen 回调函数中定时发送一个“心跳”消息,以维持与服务器的连接。代码如下:

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

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

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

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

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

这里的 setInterval 函数将会每隔 20 秒向服务器发送一个心跳消息,如果 30 秒内没有接收到任何消息,则 SSE 连接会被自动中断。

总结

通过以上方法,我们可以解决在 Chrome 浏览器下 SSE 自动中断连接的问题。需要注意的是,由于服务器和客户端可能存在时钟不同步的情况,建议在实现心跳机制时,采用时间戳进行校验,以避免不同步导致的问题。

此外,在使用 SSE 时,也应该注意控制发送的消息长度,以免触发浏览器的自动中断机制,从而达到更加稳定的连接效果。

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

纠错
反馈