htmx WebSocket 扩展

WebSocket 扩展支持直接从 HTML 与 WebSocket 服务器进行简单的双向通信。此扩展取代了早期 htmx 版本中内置的实验性 hx-ws 属性。如需从旧版本迁移的帮助,请参阅本页底部的迁移指南

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

安装

安装 ws 的最快方式是通过 CDN 加载。请记得始终在扩展之前包含核心 htmx 库,并启用扩展

<head>
    <script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.6/dist/htmx.min.js" integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/htmx-ext-ws@2.0.2" integrity="sha384-vuKxTKv5TX/b3lLzDKP2U363sOAoRo5wSvzzc3LJsbaQRSBSS+3rKKHcOx5J8doU" crossorigin="anonymous"></script>
</head>
<body hx-ext="ws">

未压缩版本也可在 https://cdn.jsdelivr.net/npm/htmx-ext-ws/dist/ws.js 获取。

虽然 CDN 方法简单,但您可能需要考虑在生产环境中不使用 CDN。下一个最简单的安装 ws 的方法就是将其复制到您的项目中。从 https://cdn.jsdelivr.net/npm/htmx-ext-ws 下载扩展,将其添加到项目的适当目录中,并在需要时使用 <script> 标签包含它。

对于 npm 风格的构建系统,您可以通过 npm 安装 ws

npm install htmx-ext-ws

安装后,您需要使用适当的工具将 node_modules/htmx-ext-ws/dist/ws.js(或 .min.js)打包。例如,您可以将扩展与来自 node_modules/htmx.org/dist/htmx.js 的 htmx 核心以及项目特定代码一起打包。

如果您使用打包器管理 JavaScript(例如 Webpack、Rollup):

import `htmx.org`;
import `htmx-ext-ws`; 

使用


<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>

配置

WebSocket 扩展支持两个配置选项:

从 WebSocket 接收消息

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

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

<!-- 默认情况下将被解释为 hx-swap-oob="true" -->
<form id="form">
    ...
</form>
<!-- 将被追加到 #notifications div 的末尾 -->
<div id="notifications" hx-swap-oob="beforeend">
    收到新消息
</div>
<!-- 将使用扩展进行交换 -->
<div id="chat_room" hx-swap-oob="morphdom">
    ....
</div>

向 WebSocket 发送消息

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

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

自动重连

如果 WebSocket 由于 Abnormal ClosureService RestartTry Again Later 而意外关闭,此扩展将尝试重新连接,直到重新建立连接。

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

// 示例重连延迟,您不应该使用它
// 因为它不如已经内置的算法好
htmx.config.wsReconnectDelay = function (retryCount) {
    return retryCount * 1000 // 返回毫秒值
}

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

事件

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

事件 - htmx:wsConnecting

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

详情

事件 - htmx:wsOpen

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

详情

事件 - htmx:wsClose

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

详情

事件 - htmx:wsError

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

详情

事件 - htmx:wsBeforeMessage

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

如果事件被取消,将不会进行进一步的处理。

事件 - htmx:wsAfterMessage

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

取消此事件无效。

事件 - htmx:wsConfigSend

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

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

详情

事件 - htmx:wsBeforeSend

在发送消息之前立即触发此事件。包括队列中的消息。此时无法修改消息。

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

详情

事件 - htmx:wsAfterSend

在发送消息之后立即触发此事件。包括队列中的消息。

取消事件无效。

详情

套接字包装器

您可能会注意到所有事件都暴露了 detail.socketWrapper 属性。此包装器包含套接字对象本身和消息队列。它还封装了重连算法。它暴露了几个成员:

此包装器可以在您的事件处理程序中使用,以监视和操作队列(例如,您可以在重新连接时重置队列),并发送额外的消息(例如,如果您想批量发送数据)。fromElt 参数是可选的,如果指定,将从指定元素触发相应的 WebSocket 事件,即 htmx:wsBeforeSendhtmx:wsAfterSend 事件,当发送您的消息时。

使用演示服务器测试

Htmx 包含一个用 Node.js 编写的演示 WebSocket 服务器,它将帮助您了解 WebSocket 的实际应用,并开始引导您自己的 WebSocket 代码。它位于 htmx-extensions 仓库的 /test/ws-sse 文件夹中。查看 /test/ws-sse/README.md 获取运行和使用测试服务器的说明。

从旧版本迁移

早期版本的 htmx 使用内置标签 hx-ws 来实现 WebSocket。此代码已迁移到一个扩展中。以下是迁移到此版本所需的步骤:

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