如何在 Ruby on Rails 中使用 Server-Sent Events 实现实时数据推送

在现代 web 应用中,实时数据推送已经成为了非常重要的功能之一。而 Server-Sent Events(简称 SSE)是一种能够实现服务器与浏览器之间持久连接的技术,其原理是利用 HTTP 长连接在服务器与客户端之间传递事件。在 Ruby on Rails 中,我们可以借助 Action Controller 中的 ActionController::Live 模块轻松地实现 SSE。

SSE 的优点

相比起 WebSocket 技术,SSE 技术更简单易用,因为它只需要使用普通的 HTTP 协议进行通信,不需要额外的协议握手操作。同时,SSE 也支持自定义事件及数据,比较适合处理简单的实时数据推送需求。

Rails 中的 SSE 实现

要在 Rails 中使用 SSE,我们需要先在控制器中引入 ActionController::Live 模块,并建立一个 respond_to 块:

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

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

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

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

---

上述代码中的 stream 方法就是我们的 SSE 推送入口。我们通过设置 HTTP 头部的 Content-Type 为 text/event-stream 使得浏览器对本次请求的响应以 SSE 的方式进行处理。然后,我们创建了一个 SSE 对象 sse,并将 response.stream 传给它,以便后续可以使用它来推送 SSE 事件。最后我们调用了 sse.close,这将通知浏览器本次 SSE 推送已经完成,浏览器也将释放连接。

在 SSE 推送逻辑中,我们可以使用 sse.write 方法向客户端发送自定义事件及其数据,例如:

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

上述代码就向客户端推送了一个名为 'my_event' 的自定义事件,其数据为 {"message": "Hello, world!"}。在浏览器端通过监听相应事件,在收到消息时就可以进行相应的处理了。例如:

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

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

上述代码中,我们通过新建一个 EventSource 对象指定事件源为 /my_controller/stream 路径约定的 SSE 推送入口。然后我们通过 addEventListener 方法监听名为 'my_event' 的自定义事件,一旦后端向客户端推送了该事件,浏览器就会在相应方法内进行相应的处理,例如给出一个弹窗显示消息内容。

权限控制、错误处理等常见问题

在实际开发中,我们还需要考虑一些常见问题,例如权限控制、错误处理等。下面是一些可能用到的技巧。

认证与授权

在某些场景下,我们可能需要对 SSE 推送进行认证与授权。例如,我们可能需要只向登陆用户发送推送消息,或者需要限制某些用户只能接收特定类型的消息。针对这种情况,我们可以在 SSE 推送入口处增加相应的认证与授权逻辑,例如:

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

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

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

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

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

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

---

上述代码中,我们在 stream 方法前加入了一个 before_action 来认证用户是否已登陆。然后根据不同用户身份确定 SSE 推送逻辑。比如管理员可以订阅所有类型消息的事件,而其他用户只能订阅特定类型消息的事件。我们创建了两个 SSE 推送方法,分别为 subscribe_all_eventssubscribe_event,代码中并未给出具体实现,重点是展示了如何针对不同用户身份订阅不同的 SSE 事件。如果用户无法订阅指定类型消息时,我们可以在 rescue 块中进行相应的处理。

错误处理

在 SSE 推送过程中,服务端、客户端都可能发生意外错误,我们需要对这些错误进行相应处理。以下是一些常见错误的处理方式。

请求过程中出现的错误

如果服务端在 SSE 推送时发生错误,例如因为客户端断开连接导致 IOError,我们需要在 rescue 块中进行相应的错误处理。例如,如果我们需要使客户端退出 SSE 推送时触发跳转到一个特定的页面,我们可以这样写:

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

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

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

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

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

---

上述代码中,我们在 rescue 块中增加了跳转逻辑,将客户端导向 /error 页面。 turbolinks: false 是为了避免 Turbolinks 的影响,确保可以正常跳转。

客户端出现的错误

如果客户端在 SSE 接收过程中出现错误,例如前端代码出错,我们可能需要对这些错误进行相应的处理。由于 SSE 推送是以持久连接的方式进行的,一旦发生错误可能会使推送过程中断,我们可以通过定时的 ping 来确认连接是否正常并使用 retry: 字段指定重新连接的时间间隔。例如:

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

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

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

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

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

---

上述代码中,我们在发送数据之前增加了一个 try-catch 块来捕获可能发生的 IOError 错误,一旦捕获到错误就关闭 SSE 推送。由于客户端出错的情况较为复杂,我们并不知道客户端什么时候出现了错误,因此我们可以在一定时间间隔后尝试重新连接服务器。如果我们使用的是 EventSource API,我们可以通过 eventSource.close() 显式关闭 SSE 连接,以便重新连接服务器。另外,如果客户端与服务器之间的连接出现了大量不可恢复的错误,最好建立一个定时任务将这些错误进行记录并给出相应提示。例如,前端代码可能出现了一些不可捕获的 JavaScript 错误,我们可以在后端监控相关的错误日志,一旦出现错误就通知用户进行相应的提示。

示例代码

示例代码是一个简单的聊天系统,可以让用户进行发送消息,并通过 SSE 进行广播。以下是服务器端的代码(参见 GitHub 源代码):

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

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

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

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

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

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

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

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

---

客户端的代码如下:

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

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

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

  ----

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

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

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

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

运行测试:

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

访问 http://localhost:3000/chats 可以看到聊天系统的页面,可以发送消息并实时接收发送记录。

总结

本文介绍了如何在 Ruby on Rails 中使用 Sever-Sent Events(SSE)实现实时数据推送,并针对认证与授权、错误处理等常见问题进行了相应解释。SSE 技术与传统的 Ajax 轮询相比,其优点在于可以让服务端向客户端主动推送消息,因此可以更加及时地响应用户操作。常见的应用场景包括聊天系统、实时数据监控等。如果您正在开发这类应用,可以尝试使用 SSE 来实现实时数据推送功能。

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


猜你喜欢

  • React Native 应用中 Redux 的最佳实践

    前言 在现代的前端开发中,Redux 已经成为了不可或缺的一部分。在 React Native 应用中,Redux 的应用越来越广泛,它为应用提供了强大的状态管理功能。

    1 年前
  • Sequelize 如何实现数据库备份和恢复?

    简介 Sequelize 是一个基于 Node.js 的 ORM(Object-Relational Mapping)框架,用于操作关系型数据库。在实际项目开发中,数据库备份和恢复是一项非常重要的工作...

    1 年前
  • 如何使用 JWT 实现 RESTful API 的身份认证

    什么是 JWT? JWT(JSON Web Token)是一种轻量级的认证和授权机制,由 JSON 数据构成,使用签名来保证传输过程中的安全性。JWT 包含一个头部、一个载荷和一个签名。

    1 年前
  • ES9 的新特性:Array.prototype.includes()

    ES9 是 ECMAScript 2018 的简称,它是 JavaScript 语言最新版本中的一部分。ES9 在语言方面新增了很多的特性和语法,其中 Array.prototype.includes...

    1 年前
  • 如何使用 Next.js + Firebase 构建 Web 应用

    本文将介绍如何使用 Next.js 和 Firebase 快速构建基于 React 的 Web 应用,并且将重点放在如何结合 Next.js 和 Firebase 的使用,以及如何进行优化与缓存方案。

    1 年前
  • Chai.js 和 Karma:在 Web 应用程序中进行测试

    Chai.js 和 Karma:在 Web 应用程序中进行测试 在现代 Web 开发中,测试已经成为了必要的一步。测试不仅能够帮助开发者保证代码的质量,还能够帮助开发者尽早发现潜在的问题,并促进团队合...

    1 年前
  • Socket.io 实现长轮询的原理及使用方法

    前言 在前端开发中,我们常常需要实时更新页面数据。而在 Web 开发早期,很多人采用轮询的方式去实现这个功能。轮询就是每隔一段时间向服务器发送请求,看看有没有新数据。

    1 年前
  • ES6 中的 Generator 函数在异步编程中的应用

    作为一名前端开发者,我们对于异步编程并不陌生。在开发过程中,我们通常使用回调函数、Promise、Async/Await 等方式来处理异步调用和数据流控制。然而,ES6 引入的 Generator 函...

    1 年前
  • RESTful API 使用过程中的最佳实践

    RESTful API 是一种标准的 Web API 设计风格,它基于 HTTP 协议和 Web 的架构原则,并且非常适合用于前端和后端之间的数据通信。在本文中,我们将介绍 RESTful API 使...

    1 年前
  • 如何利用 Next.js 实现服务端渲染和客户端渲染之间的转换?

    在现代 Web 应用中,服务端渲染和客户端渲染都是非常重要的技术手段。服务端渲染可以使得页面在首次请求时就能够快速呈现,从而提升用户体验和 SEO;而客户端渲染则可以提供更加丰富和交互性的用户界面,从...

    1 年前
  • 如何在您的 React 项目中使用 ESLint

    在现代前端开发中,JavaScript 开源工具非常丰富,ESLint 就是其中之一。ESLint 可以帮助开发者确保他们的代码符合最佳实践,减少了代码错误和技术债务,提高代码可维护性和开发效率。

    1 年前
  • 用 Sass 实现网页背景虚化效果

    在现代网页设计中,背景的虚化效果被广泛应用。这种效果可以让页面的主要内容更加突出,增强用户对页面的注意力。而通过 Sass 的变量、函数等特性,我们可以很方便地实现这种效果,并且让代码更加易于管理和扩...

    1 年前
  • Hapi 实战:如何使用 Hapi-Jsonwebtoken 插件生成 JWT Token

    什么是 JWT Token? JWT Token(Json Web Token)是一种基于JSON的开放标准,用于在不同系统中以安全的方式传输信息。JWT 由三部分组成(使用点.分隔): Heade...

    1 年前
  • 微信小程序 Webpack 打包实战总结

    前言 自从微信宣布支持小程序使用第三方框架以及扩展组件功能之后,越来越多的开发者开始思考如何将其他前端技术应用到小程序中。而其中最被广泛使用的就是 Webpack 打包工具。

    1 年前
  • Node.js 中的文件 I/O 技术详解

    什么是文件 I/O 文件 I/O 是指通过输入输出流读写文件的操作。在 Node.js 中,读写文件是常见的任务。可以使用 Node.js 提供的 fs 模块进行文件 I/O 操作。

    1 年前
  • 响应式设计中如何解决移动端虚线边框问题

    在响应式设计中,我们经常需要为移动端设备适配样式。然而,移动端设备在聚焦输入框时会出现虚线边框,这对设计和用户体验都是一种挑战。如何去除这种虚线边框并保证用户体验是一件比较困难的事情。

    1 年前
  • Vue.js 2.0+Vuex 实现登录认证流程

    Vue.js 是一个流行的前端框架,它的灵活性和易用性让开发者能够快速构建出优秀的单页面应用程序。然而,在实现需要用户登录的应用程序时,我们需要考虑如何进行用户的身份认证和授权,以及如何在应用程序中管...

    1 年前
  • 解决 Kubernetes 中 Pod 崩溃的常见问题和解决方法

    在 Kubernetes 环境下,Pod 是最小的可部署对象。Pod 由一个或多个容器组成,它们共享相同的网络和存储空间。由于某些原因,Pod 可能会崩溃,这会影响到整个应用的稳定性。

    1 年前
  • TypeScript 2.0 中的新特性是什么?

    介绍 TypeScript 是一种由微软开发的强类型的 JavaScript 超集语言,它扩展了 JavaScript,使开发者能够使用强类型和类等面向对象的特性。

    1 年前
  • 如何使用 Babel 将 ES6 转成兼容更广泛的 ES5

    在前端开发领域,我们经常会听到“ES6”这个词汇。所谓 ES6,是指 ECMAScript 6,也就是 JavaScript 的第六个版本。ES6 的出现,使得 JavaScript 语言在语法、模板...

    1 年前

相关推荐

    暂无文章