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://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):
htmx.org
和 htmx-ext-ws
index.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 服务器发送数据的任何子表单 |