htmx Web Socket 扩展

Web Sockets 扩展可让你直接从 HTML 轻松与 Web Sockets 服务器进行双向通信。这将取代先前版本中内置的实验性属性 hx-wshtmx 。如需从旧版本迁移的帮助,请参阅本页底部的迁移指南。

使用以下属性来配置 WebSocket 的行为方式:

  • ws-connect="<url>" 或 ws-connect="<prefix>:<url>"- 用于建立连接的 URL WebSocket。
  • 前缀 ws 或 wss 可选指定。如果未指定,HTMX 默认添加位置的方案类型、主机和端口,以便浏览器通过 websockets 发送 cookie。
  • ws-send- 根据元素的触发值(自然事件或 [ hx-trigger] 指定的事件)向最近的 websocket 发送消息

安装

<script src="https://unpkg.com/[email protected]/ws.js"></script>
用法

<div hx-ext="ws" ws-connect="/chatroom">
    <div id="notifications"></div>
    <div id="chat_room">
        ...
    </div>
    <form id="form" ws-send>
        <input name="chat_message">
    </form>
</div>

配置

WebSockets 扩展支持两种配置选项:

  • createWebSocket - 可用于创建自定义 WebSocket 实例的工厂函数。必须是一个函数,返回 WebSocket 对象
  • wsBinaryType - 一个字符串值,定义套接字的 binaryType 属性。默认值为blob

从 WebSocket 接收消息

上述示例建立了到 /chatroom 端点的 WebSocket。从 WebSocket 发送的内容将被解析为 HTML,并由属性进行交换,使用与带外交换 id 相同的逻辑。

因此,如果你想更改交换方法(例如,在元素末尾附加内容或将交换委托给扩展),则需要在服务器发送的消息正文中指定。

<!-- will be interpreted as hx-swap-oob="true" by default -->
<form id="form">
    ...
</form>
<!-- will be appended to #notifications div -->
<div id="notifications" hx-swap-oob="beforeend">
    New message received
</div>
<!-- will be swapped using an extension -->
<div id="chat_room" hx-swap-oob="morphdom">
    ....
</div>

向 WebSocket 发送消息

在上面的例子中,表单使用 ws-send 属性来指示在提交时,表单值应该序列化为 JSON 并发送到最近的 WebSocket,在本例中为 /chatroom 端点。

序列化的值将包括一个字段,HEADERS 中包含通常随 htmx 请求一起提交的 HTTP 头。

自动重新连接

如果 WebSocket 因异常关闭、服务重启 或 稍后重试 导致关闭。该插件将尝试重连,直到重新建立连接。

默认情况下,该扩展使用全抖动指数回退算法,该算法选择随时间呈指数增长的随机重试延迟。您可以通过将算法写入 htmx.config.wsReconnectDelay 来使用不同的算法。此函数采用单个参数,即重试次数,并返回重试前等待的时间(以毫秒为单位)。

// example reconnect delay that you shouldn't use because
// it's not as good as the algorithm that's already in place
htmx.config.wsReconnectDelay = function (retryCount) {
    return retryCount * 1000 // return value in milliseconds
}

该扩展还实现了一个简单的排队机制,当套接字处于非 OPEN 状态时将消息保存在内存中,并在连接恢复后发送它们。

事件

WebSockets 扩展公开了一组事件,允许你观察和自定义其行为。

事件 - htmx:wsConnecting

当尝试连接 WebSocket 端点时会触发此事件。

detail
  • detail.event.type - 事件的类型('connecting')

事件 - htmx:wsOpen

当建立与 WebSocket 端点的连接时触发此事件。

detail
  • detail.elt - 保存套接字的元素(具有 ws-connect 属性的元素)
  • detail.event - 来自套接字的原始事件
  • detail.socketWrapper - 套接字对象的包装器

事件 - htmx:wsClose

当与 WebSocket 端点的连接正常关闭时,会触发此事件。你可以通过检查 detail.event 属性来检查该事件是否由错误引起。

detail
  • detail.elt - 保存套接字的元素(具有 ws-connect 属性的元素)
  • detail.event - 来自套接字的原始事件
  • detail.socketWrapper - 套接字对象的包装器

事件 - htmx:wsError

当套接字上发生 onerror 事件时,会触发此事件。

detail
  • detail.elt - 保存套接字的元素(具有 ws-connect 属性的元素)
  • detail.error - 错误对象
  • detail.socketWrapper - 套接字对象的包装器

事件 - htmx:wsBeforeMessage

当套接字刚刚收到消息时会触发此事件,类似于 htmx:beforeOnLoad。此事件在任何处理发生之前触发。

如果活动被取消,则不会进行进一步的处理。

detail
  • detail.elt - 保存套接字的元素(具有 ws-connect 属性的元素)
  • detail.message - 原始消息内容
  • detail.socketWrapper - 套接字对象的包装器

事件 - htmx:wsAfterMessage

当某条消息完全被 htmx 处理,并且所有更改都已确定时,会触发此事件,类似于htmx:afterOnLoad。

取消此活动没有任何效果。

detail
  • detail.elt - 保存套接字的元素(具有 ws-connect 属性的元素)
  • detail.message - 原始消息内容
  • detail.socketWrapper - 套接字对象的包装器

事件 - htmx:wsConfigSend

准备从 ws-send 元素发送消息时会触发此事件。与 htmx:configRequest 类似,它允许你在发送之前修改消息。

如果事件被取消,则不会发生进一步的处理,也不会发送任何消息。

detail
  • detail.parameters - 请求中要提交的参数
  • detail.unfilteredParameters - 过滤前找到的 hx-params 参数
  • detail.headersHEADERS - 请求头。如果不为 false,则将附加到属性主体中
  • detail.errors - 验证错误。如果不为空,将阻止发送并触发 htmx:validation:halted 事件
  • detail.triggeringEvent - 触发发送的事件
  • detail.messageBody - 将发送到套接字的原始消息正文。未定义,可以设置为 WebSockets 支持的任何类型的值。如果设置,将覆盖默认的 JSON 序列化。如果你想使用其他格式(如 XML 或 MessagePack),则很有用
  • detail.elt- 调度发送的元素(具有 ws-send 属性的元素)
  • detail.socketWrapper - 套接字对象的包装器

事件 -htmx:wsBeforeSend

此事件在发送消息之前触发。这包括来自队列的消息。此时无法修改消息。

如果事件被取消,消息将从队列中丢弃并且不会发送。

detail
  • detail.elt - 发送请求的元素(具有 ws-connect 属性的元素)
  • detail.message - 原始消息内容
  • detail.socketWrapper - 套接字对象的包装器

事件 - htmx:wsAfterSend

发送消息后立即触发此事件。这包括来自队列的消息。

取消该活动没有任何效果。

detail
  • detail.elt - 发送请求的元素(具有 ws-connect 属性的元素)
  • detail.message - 原始消息内容
  • detail.socketWrapper - 套接字对象的包装器

套接字封装器

你可能会注意到所有事件都公开了 detail.socketWrapper 属性。此封装器保存套接字对象本身和消息队列。它还封装了重新连接算法。它公开了一些成员:

  • send(message, fromElt) - 安全地发送消息。如果套接字未打开,则消息将保留在队列中,并在套接字准备就绪时发送。
  • sendImmediately(message, fromElt) - 尝试发送消息,不管套接字状态如何,绕过队列。可能会发送失败。
  • queue - 队列中等待的一组消息。

此封装器可用于事件处理程序中,以监视和操作队列(例如,你可以在重新连接时重置队列),以及发送其他消息(例如,如果你想批量发送数据)。fromElt 参数是可选的,指定后,将在发送消息时触发来自指定元素的相应 websocket 事件,即htmx:wsBeforeSend 和 htmx:wsAfterSend 事件。

使用演示服务器进行测试

htmx 包含一个用 Node.js 编写的演示 WebSockets 服务器,可帮助你了解 WebSockets 的实际运行情况,并开始引导你自己的 WebSockets 代码。它位于 htmx-extensions 存储库的 /test/ws-sse 文件夹中。查看 /test/ws-sse/README.md 以获取有关运行和使用测试服务器的说明。

从先前版本迁移

以前版本的 htmx 使用内置标记hx-ws来实现 WebSockets。此代码已迁移到扩展中。以下是迁移到此版本所需采取的步骤:

旧属性 新属性 评论
hx-ws="" hx-ext="ws" 使用 hx-ext="ws" 属性将 WebSockets 扩展安装到任何 HTML 元素中。
hx-ws="connect:<url>" ws-connect="<url>" 向定义扩展的标签添加一个新属性 ws-connect ,以指定你正在使用的 WebSockets 服务器的 URL。
hx-ws="send" ws-send="" 添加新属性 ws-send 来标记任何应将数据发送到 WebSocket 服务器的子表单