WebSocket 扩展支持直接从 HTML 与 WebSocket 服务器进行简单的双向通信。此扩展取代了早期 htmx 版本中内置的实验性 hx-ws 属性。如需从旧版本迁移的帮助,请参阅本页底部的迁移指南。
使用以下属性配置 WebSocket 的行为:
ws-connect="<url>" 或 ws-connect="<prefix>:<url>" - 用于建立 WebSocket 连接的 URL。ws 或 wss。如果未指定,HTMX 默认会添加位置方案类型、主机和端口,以便浏览器通过 WebSocket 发送 cookie。ws-send - 根据元素的触发值(自然事件或由 [hx-trigger] 指定的事件)向最近的 WebSocket 发送消息。安装 ws 的最快方式是通过 CDN 加载。请记得始终在扩展之前包含核心 htmx 库,并启用扩展。
<head>
<script src="https://app.unpkg.com/htmx.org@latest/files/dist/htmx.min.js" integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+" crossorigin="anonymous"></script>
<script src="https://app.unpkg.com/htmx-ext-ws@latest" integrity="sha384-vuKxTKv5TX/b3lLzDKP2U363sOAoRo5wSvzzc3LJsbaQRSBSS+3rKKHcOx5J8doU" crossorigin="anonymous"></script>
</head>
<body hx-ext="ws">
未压缩版本也可在 https://app.unpkg.com/htmx-ext-ws@2.0.3/ws.js 获取。
虽然 CDN 方法简单,但您可能需要考虑在生产环境中不使用 CDN。下一个最简单的安装 ws 的方法就是将其复制到您的项目中。从 https://app.unpkg.com/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):
htmx.org 和 htmx-ext-wsindex.js 中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 扩展支持两个配置选项:
createWebSocket - 一个工厂函数,可用于创建自定义 WebSocket 实例。必须是一个返回 WebSocket 对象的函数。wsBinaryType - 一个字符串值,定义套接字的 binaryType 属性。默认值为 blob。上面的示例建立了到 /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>
在上面的示例中,表单使用 ws-send 属性来指示当它被提交时,表单值应序列化为 JSON 并发送到最近的封闭 WebSocket,在本例中是 /chatroom 端点。
序列化的值将包括一个字段 HEADERS,其中包含通常与 htmx 请求一起提交的标头。
如果 WebSocket 由于 Abnormal Closure、Service Restart 或 Try Again Later 而意外关闭,此扩展将尝试重新连接,直到重新建立连接。
默认情况下,扩展使用全抖动 指数退避算法,该算法选择一个随机化的重试延迟,随着时间的推移呈指数增长。您可以通过将其写入 htmx.config.wsReconnectDelay 来使用不同的算法。此函数接受一个参数,即重试次数,并返回再次尝试之前等待的时间(以毫秒为单位)。
// 示例重连延迟,您不应该使用它
// 因为它不如已经内置的算法好
htmx.config.wsReconnectDelay = function (retryCount) {
return retryCount * 1000 // 返回毫秒值
}
该扩展还实现了一个简单的队列机制,当套接字不处于 OPEN 状态时,将消息保留在内存中,并在连接恢复后发送它们。
WebSocket 扩展公开了一组事件,允许您观察和自定义其行为。
htmx:wsConnecting当尝试连接到 WebSocket 端点时触发此事件。
detail.event.type - 事件类型('connecting')htmx:wsOpen当成功建立到 WebSocket 端点的连接时触发此事件。
detail.elt - 持有套接字的元素(带有 ws-connect 属性的元素)detail.event - 来自套接字的原始事件detail.socketWrapper - 套接字对象的包装器htmx:wsClose当正常关闭到 WebSocket 端点的连接时触发此事件。您可以通过检查 detail.event 属性来确定事件是否由错误引起。
detail.elt - 持有套接字的元素(带有 ws-connect 属性的元素)detail.event - 来自套接字的原始事件detail.socketWrapper - 套接字对象的包装器htmx:wsError当套接字上触发 onerror 事件时触发此事件。
detail.elt - 持有套接字的元素(带有 ws-connect 属性的元素)detail.error - 错误对象detail.socketWrapper - 套接字对象的包装器htmx:wsBeforeMessage当套接字刚刚接收到消息时触发此事件,类似于 htmx:beforeOnLoad。此事件在任何处理发生之前触发。
如果事件被取消,将不会进行进一步的处理。
detail.elt - 持有套接字的元素(带有 ws-connect 属性的元素)detail.message - 原始消息内容detail.socketWrapper - 套接字对象的包装器htmx:wsAfterMessage当 htmx 完全处理完消息并且所有更改都已稳定时触发此事件,类似于 htmx:afterOnLoad。
取消此事件无效。
detail.elt - 持有套接字的元素(带有 ws-connect 属性的元素)detail.message - 原始消息内容detail.socketWrapper - 套接字对象的包装器htmx:wsConfigSend当准备从 ws-send 元素发送消息时触发此事件。类似于 htmx:configRequest,它允许您在发送前修改消息。
如果事件被取消,将不会进行进一步的处理,也不会发送任何消息。
detail.parameters - 将在请求中提交的参数detail.unfilteredParameters - 在通过 hx-params 过滤之前找到的参数detail.headers - 请求标头。如果非假值,将附加到 HEADERS 属性中的正文detail.errors - 验证错误。如果不为空,将阻止发送并触发 htmx:validation:halted 事件detail.triggeringEvent - 触发发送的事件detail.messageBody - 将发送到套接字的原始消息正文。可以是 WebSocket 支持的任何类型的值。如果设置,将覆盖默认的 JSON 序列化。如果您想使用其他格式(如 XML 或 MessagePack),这将非常有用detail.elt - 分发发送的元素(带有 ws-send 属性的元素)detail.socketWrapper - 套接字对象的包装器htmx:wsBeforeSend在发送消息之前立即触发此事件。包括队列中的消息。此时无法修改消息。
如果事件被取消,消息将从队列中丢弃,不会发送。
detail.elt - 分发请求的元素(带有 ws-connect 属性的元素)detail.message - 原始消息内容detail.socketWrapper - 套接字对象的包装器htmx:wsAfterSend在发送消息之后立即触发此事件。包括队列中的消息。
取消事件无效。
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 编写的演示 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 服务器发送数据的任何子表单 |