解决记得调用 res.end() 以关闭 EventSource 的 Server-Sent Events 问题

Server-Sent Events (简称 SSE) 是一种前端实现服务器推送的技术。借助 SSE,服务器可以主动向客户端推送数据,而不需要客户端发起请求。SSE 使用 EventSource API 在浏览器中实现。但是在使用 SSE 过程中,可能会遇到 res.end()未及时调用 导致 SSE 无法正常关闭的问题,本文将详细介绍这一问题的产生原因,并给出解决方案。

1. 问题原因

在使用 SSE 实现服务器推送消息时,常常是在发送完数据后即可关闭 SSE。下面是一个简单的发送事件流的代码示例:

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

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

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

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

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

上面的代码简单地创建了一个 HTTP 服务器,并监听端口为 3000。在处理客户端请求时,服务器代码设置了 SSE 响应头,同时每秒向客户端发送当前时间的字符串,以达到每秒向客户端推送消息的目的。但是,我们可以发现,在代码中调用了 res.write() 方法,但并没有调用 res.end() 方法来关闭 SSE。

当我们在浏览器中访问服务器地址 http://localhost:3000 时,可以发现 SSE 正常地向客户端推送消息,但当我们再次访问 http://localhost:3000 时,可以观察到消息推送依然在继续,而这将导致服务器资源被浪费,影响应用性能。

这是因为,当使用 SSE 时,服务器会同时打开两个长连接(即 HTTP 连接),一个用于 SSE,另外一个用于解析 HTTP 请求(可以通过 EventSource 构造函数的第二个参数 { withCredentials: true } 明显观察到)。由于 SSE 需要保持长连接,如果我们不及时调用 res.end() 方法关闭 SSE,那么客户端和服务器之间的 SSE 连接将一直保持打开状态,从而导致资源被占用。

2. 解决方案

解决本问题的方法非常简单,即:在 SSE 推送完毕之后,调用 res.end() 方法关闭 SSE 连接。

上面的代码中已经提到了在每次 SSE 推送数据前检查 res.finished 属性,直到 res.finished 被设置为 true 才停止定时任务。这里可以根据 res.finished 的值来判断是否需要调用 res.end() 方法。

下面是修改后的代码:

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

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

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

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

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

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

修改后的代码中,加入了一个 req.on('close', handler) 的监听器。当客户端主动关闭 SSE 连接时,服务器会触发 'close' 事件,并调用 handler 函数来关闭 SSE 连接。

这段代码的核心部分是:

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

在这个回调函数中,首先使用 clearInterval(intervalId) 来停止定时器任务。而后,通过调用 res.end() 方法来关闭 SSE 连接,并释放资源。

通过这样的处理,当客户端主动关闭 SSE 连接时,服务器就能够及时地关闭 SSE 连接,并释放相关资源,从而避免浪费资源,提高应用性能。

3. 总结

在使用 Server-Sent Events 技术时,记得调用 res.end() 以关闭 SSE 连接,从而避免资源被浪费,提高应用性能。我们可以通过监听 'close' 事件来触发服务器关闭 SSE 连接的回调函数,在回调函数中释放相关资源。

下面是上述代码的 GitHub 仓库地址,供感兴趣的读者下载学习:https://github.com/dolphin-emu/docs-cn/blob/master/articles/3-tech/frontend/1-eventsource-problem/index.js

来源:JavaScript中文网 ,转载请联系管理员! 本文地址:https://www.javascriptcn.com/post/65af51ebadd4f0e0ff8bbc2e


猜你喜欢

  • JavaScript 字符串处理的两种方式 ——indexOf 和 matchAll 是否能满足需求?ECMAScript 2021 中的整合新方法来了

    在 JavaScript 中,字符串处理是非常常见的需求,比如搜索、替换、截取等等。常用的字符串处理方法包括 indexOf 和 matchAll 等。然而,在实际使用中,我们会发现这些方法并不能完全...

    9 个月前
  • 如何使用 Fastify 和 MySQL 构建 Node.js CRUD 应用程序

    在前端开发中,服务器端的应用程序开发也是必不可少的一项技能。其中,构建一个基于 Node.js 并使用 MySQL 数据库的 CRUD 应用程序是一个基础而重要的任务。

    9 个月前
  • Deno 中如何使用第三方 REST API

    简介 Deno 是一个用于构建 Web 应用程序的 JavaScript/TypeScript 运行时,它的出现是为了解决 Node.js 中存在的一些问题。在开发过程中,我们通常需要和第三方 RES...

    9 个月前
  • Jest Mock 模块的实现原理及应用场景

    Jest 是一个流行的 JavaScript 测试框架,它提供了强大的断言、模拟和 Mock 功能。Mock 功能是 Jest 中的一个重要特性,它允许我们模拟网络请求、外部依赖、程序内部模块等功能,...

    9 个月前
  • 如何在 LESS 中使用条件语句来处理 CSS 样式

    前言 LESS 是一种动态样式语言,它扩展了 CSS,并在其基础上添加了诸多功能,例如变量、混合(mixin)、嵌套规则等等。但是,有些情况下,我们需要根据不同的条件生成不同的 CSS 样式,这时候,...

    9 个月前
  • 畅享 ES8 的新特性 ——SharedArrayBuffer

    在 ES8(ECMAScript 2017)标准中,引入了一项新的并发编程特性:SharedArrayBuffer。SharedArrayBuffer 是一种类数组对象,它允许多个 JavaScrip...

    9 个月前
  • Redux 状态管理之神器 ——combineReducers

    随着前端技术的不断发展,状态管理成为了不可避免的问题。而 Redux 作为一个强大的状态管理库,已经成为了前端开发者的常用工具。在 Redux 中,combineReducers 方法则是状态管理之中...

    9 个月前
  • Kubernetes 的命名空间简介及使用方法详解

    前言 Kubernetes 是一个开源的容器编排系统,它可以帮助我们管理和部署容器化应用。在实际的应用场景中,我们可能需要同时运行多个应用,这时候,就需要对这些应用进行分类管理,以便更好地进行维护和管...

    9 个月前
  • CSS3 布局方式之 Flex 布局详解

    CSS3 中新增的 Flex 布局方式是响应式网页设计中的一大利器,它使得设计师可以轻松实现各种复杂的布局效果,同时也提高了网页的灵活性和可读性。本文将详细介绍 Flex 布局的基础概念、使用方法和实...

    9 个月前
  • Tailwind 中的 SVG 图标处理技巧详解

    SVG 是静态矢量图形格式,可以让我们在不损失图像质量的情况下放大或缩小图像。SVG 图标在现代 Web 开发中非常常见,因此 Tailwind 提供了一些方便的方法来处理 SVG 图标。

    9 个月前
  • 如何使用 ESLint 进行 no-shadow 检查

    ESLint 是一个非常有用的 JavaScript 代码检查工具,它可以帮助开发者保证代码的质量和风格的统一性,避免出现潜在的错误和严重的安全漏洞。在本文中,我们将介绍如何使用 ESLint 进行 ...

    9 个月前
  • MongoDB 更新文档报错 “too much data for sort”

    在进行 MongoDB 数据库操作时,更新文档是十分常见的操作,但是在更新大量数据的情况下,有时会出现报错“too much data for sort”。这个错误是 MongoDB 在执行 sort...

    9 个月前
  • ES10 中增强版的 Array.prototype.reduce() 方法解决数组操作问题

    介绍 在 ES10 中, Array.prototype.reduce() 方法进行了一些增强,其中最有用的功能是可以通过异步函数实现并行数组操作。这种并行操作在处理大型数据集和耗时的操作时非常有用。

    9 个月前
  • Enzyme 框架在测试 React Native 应用中的使用介绍

    React Native 是一个流行的移动端开发框架,它可以快速构建高质量的原生应用程序。在开发 React Native 应用程序时,我们需要保证应用程序的稳定性和可靠性,这就需要进行测试。

    9 个月前
  • 了解 ES9 中新增的词法范围内的 this 语法

    JavaScript 中的 this 关键字一直是令人头疼的问题之一。有时它的值不是预期的,而且它的行为也经常难以预测。 ES6 引入了块级作用域,其中的 let 和 const 与 var 不同,可...

    9 个月前
  • Fastify 和 Express:它们之间的主要区别是什么?

    在前端领域,Node.js 是非常流行的一种技术,它可以用来构建高度可伸缩的 Web 应用程序。在 Node.js 中,Express 是目前最流行的框架之一。然而,Fastify 是一个相对较新的框...

    9 个月前
  • 细说 Jest 的 Mock 模块和 Spy 模块

    在前端开发中,单元测试是不可或缺的一部分。而 Jest 作为一个广泛应用的 JavaScript 测试框架,提供了丰富的工具来协助我们编写高质量的测试用例。其中,Mock 模块和 Spy 模块是 Je...

    9 个月前
  • 无障碍设计的 10 个技巧

    随着互联网技术的发展,越来越多的人通过网络获取信息。但是,我们也需要意识到,仍然有大量残疾人、老年人等用户面临着无法访问无障碍界面的问题。因此,为了实现真正的无障碍设计,我们需要考虑这些用户的需求。

    9 个月前
  • 在 LESS 中使用 Mixin 和 Extend 的最佳实践

    在前端开发中,使用预处理器已经成为了一种必备技能。LESS 是其中一个比较流行的 CSS 预处理器,它可以让我们更加快速、高效地书写样式,同时也支持 Mixin 和 Extend 两种功能。

    9 个月前
  • Kubernetes 中的分区分隔方法与策略详解

    前言 随着云计算的普及,容器技术逐渐成为应用程序开发及部署的主流方式,而 Kubernetes 就是目前最流行的容器编排系统。Kubernetes 中的分区分隔机制可以帮助我们更好地管理容器中的应用程...

    9 个月前

相关推荐

    暂无文章