更多内容请访问 rubyonrails.org:

Action Cable 概述

在本指南中,您将学习 Action Cable 的工作原理以及如何使用 WebSockets 将实时功能集成到您的 Rails 应用程序中。

阅读本指南后,您将了解

  • Action Cable 是什么以及它的后端和前端集成
  • 如何设置 Action Cable
  • 如何设置频道
  • 运行 Action Cable 的部署和架构设置

1. 什么是 Action Cable?

Action Cable 将 WebSockets 与您的 Rails 应用程序其余部分无缝集成。它允许以与 Rails 应用程序其他部分相同的风格和形式用 Ruby 编写实时功能,同时保持高性能和可扩展性。它是一个全栈产品,提供客户端 JavaScript 框架和服务器端 Ruby 框架。您可以访问使用 Active Record 或您选择的 ORM 编写的整个领域模型。

2. 术语

Action Cable 使用 WebSockets 而不是 HTTP 请求-响应协议。Action Cable 和 WebSockets 都引入了一些不那么熟悉的术语。

2.1. 连接

连接构成了客户端-服务器关系的基础。单个 Action Cable 服务器可以处理多个连接实例。每个 WebSocket 连接都有一个连接实例。如果单个用户使用多个浏览器标签页或设备,他们可能会打开多个 WebSocket 连接到您的应用程序。

2.2. 消费者

WebSocket 连接的客户端称为消费者。在 Action Cable 中,消费者由客户端 JavaScript 框架创建。

2.3. 频道

每个消费者又可以订阅多个频道。每个频道都封装了一个逻辑工作单元,类似于控制器在典型 MVC 设置中的作用。例如,您可以有一个 ChatChannel 和一个 AppearancesChannel,消费者可以订阅其中一个或两个频道。至少,消费者应该订阅一个频道。

2.4. 订阅者

当消费者订阅一个频道时,他们就充当了订阅者。订阅者和频道之间的连接,不出所料,被称为订阅。一个消费者可以多次充当给定频道的订阅者。例如,一个消费者可以同时订阅多个聊天室。(请记住,一个物理用户可能有多个消费者,每个打开的标签/设备一个连接)。

2.5. 发布/订阅

发布/订阅 或 Pub/Sub 指的是一种消息队列范式,其中信息发送方(发布者)将数据发送给抽象的接收方类别(订阅者),而无需指定单个接收方。Action Cable 使用这种方法在服务器和多个客户端之间进行通信。

2.6. 广播

广播是一种发布/订阅链接,其中广播器传输的任何内容都直接发送给正在流式传输该命名广播的频道订阅者。每个频道可以流式传输零个或多个广播。

3. 服务器端组件

3.1. 连接

对于服务器接受的每个 WebSocket,都会实例化一个连接对象。该对象成为从那时起创建的所有频道订阅的父级。连接本身除了身份验证和授权之外,不处理任何特定的应用程序逻辑。WebSocket 连接的客户端称为连接消费者。单个用户将在他们打开的每个浏览器标签页、窗口或设备上创建一个消费者-连接对。

连接是 ApplicationCable::Connection 的实例,它扩展了 ActionCable::Connection::Base。在 ApplicationCable::Connection 中,您授权传入连接,如果用户可以被识别,则继续建立它。

3.1.1. 连接设置

# app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    private
      def find_verified_user
        if verified_user = User.find_by(id: cookies.encrypted[:user_id])
          verified_user
        else
          reject_unauthorized_connection
        end
      end
  end
end

此处 identified_by 指定了一个连接标识符,可用于以后查找特定连接。请注意,任何被标记为标识符的内容都会自动在从连接创建的任何频道实例上创建同名委托。

此示例依赖于您已在应用程序的其他地方处理了用户身份验证的事实,并且成功的身份验证会设置一个带有用户 ID 的加密 cookie。

然后,在尝试建立新连接时,cookie 会自动发送到连接实例,您可以使用它来设置 current_user。通过使用相同的当前用户识别连接,您还可以确保以后可以通过给定用户检索所有打开的连接(并在用户被删除或未经授权时可能断开所有连接)。

如果您的身份验证方法包括使用会话,您使用 cookie 存储会话,您的会话 cookie 名为 _session 并且用户 ID 键为 user_id,您可以使用这种方法。

verified_user = User.find_by(id: cookies.encrypted["_session"]["user_id"])

3.1.2. 异常处理

默认情况下,未处理的异常会被捕获并记录到 Rails 的日志中。如果您想全局拦截这些异常并将其报告给外部错误跟踪服务(例如),您可以使用 rescue_from 来实现。

# app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    rescue_from StandardError, with: :report_error

    private
      def report_error(e)
        SomeExternalBugtrackingService.notify(e)
      end
  end
end

3.1.3. 连接回调

ActionCable::Connection::Callbacks 提供在向客户端发送命令时(例如订阅、取消订阅或执行操作时)调用的回调钩子。

3.2. 频道

频道封装了一个逻辑工作单元,类似于控制器在典型 MVC 设置中的作用。默认情况下,当您第一次使用频道生成器时,Rails 会创建一个父 ApplicationCable::Channel 类(它扩展了 ActionCable::Channel::Base),用于封装您的频道之间的共享逻辑。

3.2.1. 父频道设置

# app/channels/application_cable/channel.rb
module ApplicationCable
  class Channel < ActionCable::Channel::Base
  end
end

您自己的频道类可能看起来像这些示例

# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
end
# app/channels/appearance_channel.rb
class AppearanceChannel < ApplicationCable::Channel
end

然后,消费者可以订阅其中一个或两个频道。

3.2.2. 订阅

消费者订阅频道,充当订阅者。他们的连接称为订阅。然后,生成的邮件根据频道消费者发送的标识符路由到这些频道订阅。

# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  # Called when the consumer has successfully
  # become a subscriber to this channel.
  def subscribed
  end
end

3.2.3. 异常处理

ApplicationCable::Connection 一样,您也可以在特定频道上使用 rescue_from 来处理引发的异常。

# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  rescue_from "MyError", with: :deliver_error_message

  private
    def deliver_error_message(e)
      # broadcast_to(...)
    end
end

3.2.4. 频道回调

ActionCable::Channel::Callbacks 提供在频道生命周期中调用的回调钩子。

4. 客户端组件

4.1. 连接

消费者需要连接的实例。可以使用以下由 Rails 默认生成的 JavaScript 来建立连接。

4.1.1. 连接消费者

// app/javascript/channels/consumer.js
// Action Cable provides the framework to deal with WebSockets in Rails.
// You can generate new channels where WebSocket features live using the `bin/rails generate channel` command.

import { createConsumer } from "@rails/actioncable"

export default createConsumer()

这将准备一个消费者,默认情况下它会连接到服务器上的 /cable。直到您指定了至少一个您感兴趣的订阅,连接才会建立。

消费者可以选择性地接受一个参数,该参数指定要连接的 URL。这可以是一个字符串,也可以是一个返回字符串的函数,该函数将在 WebSocket 打开时调用。

// Specify a different URL to connect to
createConsumer('wss://example.com/cable')
// Or when using websockets over HTTP
createConsumer('https://ws.example.com/cable')

// Use a function to dynamically generate the URL
createConsumer(getWebSocketURL)

function getWebSocketURL() {
  const token = localStorage.get('auth-token')
  return `wss://example.com/cable?token=${token}`
}

4.1.2. 订阅者

消费者通过创建对给定频道的订阅而成为订阅者

// app/javascript/channels/chat_channel.js
import consumer from "./consumer"

consumer.subscriptions.create({ channel: "ChatChannel", room: "Best Room" })

// app/javascript/channels/appearance_channel.js
import consumer from "./consumer"

consumer.subscriptions.create({ channel: "AppearanceChannel" })

虽然这创建了订阅,但响应接收数据所需的功能将在稍后描述。

一个消费者可以多次充当给定频道的订阅者。例如,一个消费者可以同时订阅多个聊天室。

// app/javascript/channels/chat_channel.js
import consumer from "./consumer"

consumer.subscriptions.create({ channel: "ChatChannel", room: "1st Room" })
consumer.subscriptions.create({ channel: "ChatChannel", room: "2nd Room" })

5. 客户端-服务器交互

5.1.

提供了频道将其发布的内容(广播)路由给订阅者的机制。例如,以下代码使用 stream_from 订阅名为 chat_Best Room 的广播,当 :room 参数的值为 "Best Room" 时。

# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "chat_#{params[:room]}"
  end
end

然后,在您的 Rails 应用程序的其他地方,您可以通过调用 broadcast 向这样的房间广播。

ActionCable.server.broadcast("chat_Best Room", { body: "This Room is Best Room." })

如果您有一个与模型相关的流,那么广播名称可以从频道和模型生成。例如,以下代码使用 stream_for 订阅一个像 posts:Z2lkOi8vVGVzdEFwcC9Qb3N0LzE 这样的广播,其中 Z2lkOi8vVGVzdEFwcC9Qb3N0LzE 是 Post 模型的 GlobalID。

class PostsChannel < ApplicationCable::Channel
  def subscribed
    post = Post.find(params[:id])
    stream_for post
  end
end

然后,您可以通过调用 broadcast_to 向此频道广播。

PostsChannel.broadcast_to(@post, @comment)

5.2. 广播

广播是一种发布/订阅链接,其中发布者传输的任何内容都直接路由到正在流式传输该命名广播的频道订阅者。每个频道可以流式传输零个或多个广播。

广播纯粹是一个在线队列,并且具有时间依赖性。如果消费者没有流式传输(未订阅给定频道),那么即使他们稍后连接,也不会收到广播。

5.3. 订阅

当消费者订阅一个频道时,他们充当订阅者。此连接称为订阅。然后,传入的消息根据电缆消费者发送的标识符路由到这些频道订阅。

// app/javascript/channels/chat_channel.js
import consumer from "./consumer"

consumer.subscriptions.create({ channel: "ChatChannel", room: "Best Room" }, {
  received(data) {
    this.appendLine(data)
  },

  appendLine(data) {
    const html = this.createLine(data)
    const element = document.querySelector("[data-chat-room='Best Room']")
    element.insertAdjacentHTML("beforeend", html)
  },

  createLine(data) {
    return `
      <article class="chat-line">
        <span class="speaker">${data["sent_by"]}</span>
        <span class="body">${data["body"]}</span>
      </article>
    `
  }
})

5.4. 向频道传递参数

您可以在创建订阅时从客户端向服务器端传递参数。例如

# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "chat_#{params[:room]}"
  end
end

作为 subscriptions.create 的第一个参数传递的对象成为电缆频道中的 params 哈希。关键字 channel 是必需的。

// app/javascript/channels/chat_channel.js
import consumer from "./consumer"

consumer.subscriptions.create({ channel: "ChatChannel", room: "Best Room" }, {
  received(data) {
    this.appendLine(data)
  },

  appendLine(data) {
    const html = this.createLine(data)
    const element = document.querySelector("[data-chat-room='Best Room']")
    element.insertAdjacentHTML("beforeend", html)
  },

  createLine(data) {
    return `
      <article class="chat-line">
        <span class="speaker">${data["sent_by"]}</span>
        <span class="body">${data["body"]}</span>
      </article>
    `
  }
})
# Somewhere in your app this is called, perhaps
# from a NewCommentJob.
ActionCable.server.broadcast(
  "chat_#{room}",
  {
    sent_by: "Paul",
    body: "This is a cool chat app."
  }
)

5.5. 重新广播消息

一个常见的用例是重新广播一个客户端发送的消息到任何其他已连接的客户端。

# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "chat_#{params[:room]}"
  end

  def receive(data)
    ActionCable.server.broadcast("chat_#{params[:room]}", data)
  end
end
// app/javascript/channels/chat_channel.js
import consumer from "./consumer"

const chatChannel = consumer.subscriptions.create({ channel: "ChatChannel", room: "Best Room" }, {
  received(data) {
    // data => { sent_by: "Paul", body: "This is a cool chat app." }
  }
})

chatChannel.send({ sent_by: "Paul", body: "This is a cool chat app." })

重新广播将由所有连接的客户端接收,包括发送消息的客户端。请注意,params 与您订阅频道时相同。

6. 全栈示例

以下设置步骤对两个示例都是通用的

  1. 设置您的连接.
  2. 设置您的父频道.
  3. 连接您的消费者.

6.1. 示例 1:用户在线状态

这是一个简单的频道示例,它跟踪用户是否在线以及他们在哪个页面。(这对于创建存在性功能很有用,例如在用户名旁边显示一个绿点,如果他们在线的话)。

创建服务器端在线状态频道

# app/channels/appearance_channel.rb
class AppearanceChannel < ApplicationCable::Channel
  def subscribed
    current_user.appear
  end

  def unsubscribed
    current_user.disappear
  end

  def appear(data)
    current_user.appear(on: data["appearing_on"])
  end

  def away
    current_user.away
  end
end

当订阅开始时,subscribed 回调被触发,我们借此机会说“当前用户确实出现了”。该出现/消失 API 可以由 Redis、数据库或任何其他方式支持。

创建客户端在线状态频道订阅

// app/javascript/channels/appearance_channel.js
import consumer from "./consumer"

consumer.subscriptions.create("AppearanceChannel", {
  // Called once when the subscription is created.
  initialized() {
    this.update = this.update.bind(this)
  },

  // Called when the subscription is ready for use on the server.
  connected() {
    this.install()
    this.update()
  },

  // Called when the WebSocket connection is closed.
  disconnected() {
    this.uninstall()
  },

  // Called when the subscription is rejected by the server.
  rejected() {
    this.uninstall()
  },

  update() {
    this.documentIsActive ? this.appear() : this.away()
  },

  appear() {
    // Calls `AppearanceChannel#appear(data)` on the server.
    this.perform("appear", { appearing_on: this.appearingOn })
  },

  away() {
    // Calls `AppearanceChannel#away` on the server.
    this.perform("away")
  },

  install() {
    window.addEventListener("focus", this.update)
    window.addEventListener("blur", this.update)
    document.addEventListener("turbo:load", this.update)
    document.addEventListener("visibilitychange", this.update)
  },

  uninstall() {
    window.removeEventListener("focus", this.update)
    window.removeEventListener("blur", this.update)
    document.removeEventListener("turbo:load", this.update)
    document.removeEventListener("visibilitychange", this.update)
  },

  get documentIsActive() {
    return document.visibilityState === "visible" && document.hasFocus()
  },

  get appearingOn() {
    const element = document.querySelector("[data-appearing-on]")
    return element ? element.getAttribute("data-appearing-on") : null
  }
})

6.1.1. 客户端-服务器交互

  1. 客户端通过 createConsumer() 连接到服务器。(consumer.js)。服务器通过 current_user 识别此连接。

  2. 客户端通过 consumer.subscriptions.create({ channel: "AppearanceChannel" }) 订阅在线状态频道。(appearance_channel.js)

  3. 服务器识别到在线状态频道已发起新订阅,并运行其 subscribed 回调,调用 current_user 上的 appear 方法。(appearance_channel.rb)

  4. 客户端识别到已建立订阅并调用 connected (appearance_channel.js),这又会调用 installappearappear 调用服务器上的 AppearanceChannel#appear(data),并提供数据哈希 { appearing_on: this.appearingOn }。这之所以可能,是因为服务器端频道实例自动公开类上声明的所有公共方法(减去回调),以便可以通过订阅的 perform 方法作为远程过程调用来访问这些方法。

  5. 服务器接收到由 current_user 识别的连接(appearance_channel.rb)的在线状态频道上的 appear 动作请求。服务器从数据哈希中检索带有 :appearing_on 键的数据,并将其设置为传递给 current_user.appear:on 键的值。

6.2. 示例 2:接收新的网络通知

在线状态示例是关于通过 WebSocket 连接将服务器功能暴露给客户端调用。但 WebSockets 的伟大之处在于它是一个双向通道。所以,现在让我们展示一个服务器在客户端上调用动作的示例。

这是一个网络通知频道,允许您在广播到相关流时触发客户端网络通知。

创建服务器端网络通知频道

# app/channels/web_notifications_channel.rb
class WebNotificationsChannel < ApplicationCable::Channel
  def subscribed
    stream_for current_user
  end
end

创建客户端网络通知频道订阅

// app/javascript/channels/web_notifications_channel.js
// Client-side which assumes you've already requested
// the right to send web notifications.
import consumer from "./consumer"

consumer.subscriptions.create("WebNotificationsChannel", {
  received(data) {
    new Notification(data["title"], { body: data["body"] })
  }
})

从应用程序的其他地方向网络通知频道实例广播内容

# Somewhere in your app this is called, perhaps from a NewCommentJob
WebNotificationsChannel.broadcast_to(
  current_user,
  title: "New things!",
  body: "All the news fit to print"
)

WebNotificationsChannel.broadcast_to 调用将消息放置在当前订阅适配器的 pubsub 队列中,每个用户都有一个单独的广播名称。对于 ID 为 1 的用户,广播名称将是 web_notifications:1

频道已被指示将到达 web_notifications:1 的所有内容直接流式传输到客户端,方法是调用 received 回调。作为参数传递的数据是作为第二个参数发送到服务器端广播调用的哈希,经过 JSON 编码以便通过线路传输,并解包为作为 received 到达的数据参数。

6.3. 更完整的示例

请参阅 rails/actioncable-examples 存储库,了解如何在 Rails 应用程序中设置 Action Cable 并添加频道的完整示例。

7. 配置

Action Cable 有两个必需的配置:订阅适配器和允许的请求来源。

7.1. 订阅适配器

默认情况下,Action Cable 在 config/cable.yml 中查找配置文件。该文件必须为每个 Rails 环境指定一个适配器。有关适配器的更多信息,请参阅依赖项部分。

development:
  adapter: async

test:
  adapter: test

production:
  adapter: redis
  url: redis://10.10.3.153:6381
  channel_prefix: appname_production

7.1.1. 适配器配置

以下是可供最终用户使用的订阅适配器列表。

7.1.1.1. 异步适配器

异步适配器用于开发/测试,不应用于生产环境。

异步适配器仅在同一进程中工作,因此要从控制台手动触发电缆更新并在浏览器中查看结果,您必须从 Web 控制台(在开发进程中运行)执行此操作,而不是通过 bin/rails console 启动的终端!在任何操作或任何 ERB 模板视图中添加 console 以使 Web 控制台出现。

7.1.1.2. Solid Cable 适配器

Solid Cable 适配器是一个基于数据库的解决方案,它使用 Active Record。它已与 MySQL、SQLite 和 PostgreSQL 进行过测试。运行 bin/rails solid_cable:install 将自动设置 config/cable.yml 并创建 db/cable_schema.rb。之后,您必须手动更新 config/database.yml,根据您的数据库进行调整。请参阅 Solid Cable 安装

7.1.1.3. Redis 适配器

Redis 适配器要求用户提供指向 Redis 服务器的 URL。此外,可以提供一个 channel_prefix,以避免在使用同一 Redis 服务器进行多个应用程序时出现频道名称冲突。有关更多详细信息,请参阅 Redis Pub/Sub 文档

Redis 适配器还支持 SSL/TLS 连接。所需的 SSL/TLS 参数可以在配置 YAML 文件中的 ssl_params 键中传递。

production:
  adapter: redis
  url: rediss://10.10.3.153:tls_port
  channel_prefix: appname_production
  ssl_params:
    ca_file: "/path/to/ca.crt"

传递给 ssl_params 的选项直接传递给 OpenSSL::SSL::SSLContext#set_params 方法,并且可以是 SSL 上下文的任何有效属性。请参阅 OpenSSL::SSL::SSLContext 文档 以了解其他可用属性。

如果您在防火墙后使用自签名证书用于 redis 适配器并选择跳过证书检查,则 ssl verify_mode 应设置为 OpenSSL::SSL::VERIFY_NONE

不建议在生产环境中使用 VERIFY_NONE,除非您完全了解其安全隐患。为了为 Redis 适配器设置此选项,配置应为 ssl_params: { verify_mode: <%= OpenSSL::SSL::VERIFY_NONE %> }

7.1.1.4. PostgreSQL 适配器

PostgreSQL 适配器使用 Active Record 的连接池,因此应用程序的 config/database.yml 数据库配置作为其连接。这将来可能会改变。#27214

PostgreSQL 对 NOTIFY(内部用于发送通知的命令)有 8000 字节的限制,这在处理大载荷时可能是一个限制。

7.2. 允许的请求来源

Action Cable 只接受来自指定来源的请求,这些来源作为数组传递给服务器配置。来源可以是字符串或正则表达式的实例,将对其执行匹配检查。

config.action_cable.allowed_request_origins = ["https://rubyonrails.com", %r{http://ruby.*}]

要禁用并允许来自任何来源的请求

config.action_cable.disable_request_forgery_protection = true

默认情况下,Action Cable 在开发环境中运行时允许来自 localhost:3000 的所有请求。

7.3. 消费者配置

要配置 URL,请在您的 HTML 布局 HEAD 中添加对 action_cable_meta_tag 的调用。这通常使用在环境配置文件中通过 config.action_cable.url 设置的 URL 或路径。

7.4. 工作池配置

工作池用于将连接回调和频道操作与服务器主线程隔离运行。Action Cable 允许应用程序配置工作池中同时处理的线程数。

config.action_cable.worker_pool_size = 4

另请注意,您的服务器必须提供至少与您拥有的工人数量相同的数据库连接。默认工作池大小设置为 4,这意味着您必须至少提供 4 个数据库连接。您可以通过 pool 属性在 config/database.yml 中更改此设置。

7.5. 客户端日志记录

客户端日志记录默认禁用。您可以通过将 ActionCable.logger.enabled 设置为 true 来启用此功能。

import * as ActionCable from '@rails/actioncable'

ActionCable.logger.enabled = true

7.6. 其他配置

另一个常见的配置选项是应用于每个连接日志记录器的日志标签。这是一个示例,它使用用户帐户 ID(如果可用),否则在标记时使用“no-account”。

config.action_cable.log_tags = [
  -> request { request.env["user_account_id"] || "no-account" },
  :action_cable,
  -> request { request.uuid }
]

有关所有配置选项的完整列表,请参阅 ActionCable::Server::Configuration 类。

8. 运行独立的 Cable 服务器

Action Cable 可以作为 Rails 应用程序的一部分运行,也可以作为独立的服务器运行。在开发环境中,作为 Rails 应用程序的一部分运行通常很好,但在生产环境中,您应该将其作为独立的服务器运行。

8.1. 在应用程序中

Action Cable 可以与您的 Rails 应用程序一起运行。例如,要监听 /websocket 上的 WebSocket 请求,请将该路径指定给 config.action_cable.mount_path

# config/application.rb
class Application < Rails::Application
  config.action_cable.mount_path = "/websocket"
end

如果在布局中调用了 action_cable_meta_tag,您可以使用 ActionCable.createConsumer() 连接到电缆服务器。否则,路径被指定为 createConsumer 的第一个参数(例如 ActionCable.createConsumer("/websocket"))。

对于您创建的服务器的每个实例,以及您的服务器生成的每个工作程序,您也将拥有一个新的 Action Cable 实例,但 Redis 或 PostgreSQL 适配器会使消息在连接之间保持同步。

8.2. 独立

电缆服务器可以与您的普通应用程序服务器分离。它仍然是一个 Rack 应用程序,但它是一个独立的 Rack 应用程序。推荐的基本设置如下:

# cable/config.ru
require_relative "../config/environment"
Rails.application.eager_load!

run ActionCable.server

然后启动服务器

$ bundle exec puma -p 28080 cable/config.ru

这将在端口 28080 上启动一个电缆服务器。要告诉 Rails 使用此服务器,请更新您的配置。

# config/environments/development.rb
Rails.application.configure do
  config.action_cable.mount_path = nil
  config.action_cable.url = "ws://:28080" # use wss:// in production
end

最后,确保您已正确配置了消费者

8.3. 注意事项

WebSocket 服务器无法访问会话,但可以访问 cookie。当您需要处理身份验证时,可以使用此功能。您可以在这篇文章中看到一种使用 Devise 实现此目的的方法。

9. 依赖项

Action Cable 提供了一个订阅适配器接口来处理其 pubsub 内部。默认情况下,包含异步、内联、PostgreSQL 和 Redis 适配器。新 Rails 应用程序中的默认适配器是异步 (async) 适配器。

Ruby 方面是基于 websocket-drivernio4rconcurrent-ruby 构建的。

10. 部署

Action Cable 由 WebSockets 和线程组合驱动。框架的管道和用户指定的频道工作都通过利用 Ruby 的原生线程支持在内部处理。这意味着您可以毫无问题地使用所有现有的 Rails 模型,只要您没有犯任何线程安全方面的错误。

Action Cable 服务器实现了 Rack socket 劫持 API,从而允许在内部使用多线程模式管理连接,无论应用程序服务器是否为多线程。

因此,Action Cable 可与 Unicorn、Puma 和 Passenger 等流行服务器配合使用。

11. 测试

您可以在测试指南中找到有关如何测试 Action Cable 功能的详细说明。



回到顶部