使用 Server-sent 事件在 Ruby on Rails 和小程序中构建长轮询的实时通讯系统

在现代的 Web 应用程序中,实现实时通讯已经成为了一项非常常见的需求。这样的需求可以通过长轮询技术来实现。在本文中,我们将探讨如何使用 Server-sent 事件在 Ruby on Rails 和小程序中构建长轮询的实时通讯系统。

什么是长轮询?

长轮询(Long Polling)是实现实时通讯的一种技术,它的原理是:客户端向服务器发送请求,服务器在没有数据可返回时,保持连接打开并持续等待,直到有新的数据可以返回。当服务器有数据可返回时,直接将数据响应给客户端,随后关闭连接。客户端在接收到数据后,可以再次发起请求重复上述过程达到实时通讯的目的。

长轮询的好处在于,与传统的轮询相比,可以减少套接字的开启和关闭次数,从而减轻服务器的负担,并提高实时性。

Server-sent 事件是什么?

Server-sent 事件(Server-sent Events)是一种 HTML5 技术,它允许服务器单向地向客户端推送数据。在使用 SSE 时,客户端通过 EventSource API 来与服务器通信,服务器通过向客户端发送 text/event-stream 类型的数据流的方式来与客户端通信。

与 WebSocket 技术相比,SSE 更加轻量级,且支持在浏览器和移动应用中使用。

实现长轮询的 Server-sent 事件流

我们首先介绍如何在 Ruby on Rails 中使用 Server-sent 事件来实现长轮询通讯。我们将假设我们已经有了一个授权用户可以查看的信息流,并且需要在新的消息到来时实时通知用户。

Rails 的控制器端点

首先,在 Rails 应用中创建一个名为“EventsController”的控制器,然后在其中创建一个名为“streams”方法的端点。代码如下:

class EventsController < ApplicationController
  include ActionController::Live
  
  def streams
    response.headers['Content-Type'] = 'text/event-stream'
  
    sse = ServerSentEvent.new(session.id)
    sse.on_close do
      sse.close
    end
  
    redis = Redis.new
  
    redis.subscribe('stream-message') do |on|
      on.message do |event, data|
        sse.write({ message: data }, event: 'message')
      end
    end
  ensure
    redis.quit
  end
end

上述代码使用了 ActionController::Live 模块来打开长链接。然后它创建了一个名为‘Stream’的方法,并设置返回类型为 text/event-stream,从而与客户端建立 SSE 长链接。 SSE 的“on_close”方法用来为 SSE 结束事件提供侦听器,并且它在 SSE 连接关闭时被调用用于回收资源。

最后,订阅了 Redis 数据库的“stream-message”通道,从而在有新的消息到达时向客户端发出 SSE 通知。

客户端 JavaScript

在客户端,我们使用 EventSource API 来与“streams”方法建立 SSE 长链接,并在新数据流到来时执行特定的操作。代码如下:

let eventSource = new EventSource("/events/streams");

eventSource.onmessage = function(event) {
  let data = JSON.parse(event.data);
  if (data.event === 'message') {
    showMessage(data.message);
  }
}

function showMessage(message) {
  console.log(message);
}

在上面的代码中,我们使用了“onmessage”事件来处理来自服务器的任何事件。当事件的“event”属性为“message”时,执行“showMessage”方法用于显示新的信息。

使用小程序实现 Server-sent 事件流

在小程序中,我们可以使用小程序提供的 API 直接与服务器进行 SSE 通讯,这里我们将使用 WxServerSentEventStream 封装库来简化这个过程。

import { WxServerSentEventStream } from 'wx-server-sent-event-stream';

let eventSource = new WxServerSentEventStream({
  url: 'https://example.com/events/streams',
  logger: console,
});

eventSource.addEventListener('message', (event) => {
  let data = JSON.parse(event.data);
  if (data.event === 'message') {
    showMessage(data.message);
  }
});

function showMessage(message) {
  console.log(message);
}

在上述代码中,我们使用 WxServerSentEventStream 封装来访问 SSE API。我们仅需指定 SSE URL 和日志记录器即可,与在浏览器中访问 SSE API 没有什么区别。

总结

通过本文,我们了解了如何使用 Server-sent 事件流来实现长轮询实时通讯。在 Rails 应用中,我们创建了一个名为“EventsController”的控制器,并使用 SSE 封装连接 Redis 服务器,并推送最新的流信息。在客户端上,我们使用了 HTML5 中的 EventSource API 与服务器建立 SSE 长链接。

在小程序中,我们使用 WxServerSentEventStream 封装来实现了类似的功能。

通过使用 Server-sent 事件流,我们可以实现高效的实时通讯,并减轻服务器的负载压力。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a0e74cadd4f0e0ff9162ed


纠错反馈