Web Sockets 扩展实现了从 HTML 直接与 Web Sockets 服务器进行简单、双向通信的功能。这取代了 htmx 之前版本中内置的实验性 hx-ws 属性。有关从旧版本迁移的帮助,请参阅本页底部的 Migrating 指南。
使用以下属性来配置 WebSockets 的行为:
ws-connect="<url>" 或 ws-connect="<prefix>:<url>" - 用于建立 WebSocket 连接的 URL。ws 或 wss。如果未指定,HTMX 默认会添加位置的方案类型、主机和端口,以便浏览器通过 WebSockets 发送 Cookie。ws-send - 根据元素触发值(自然事件或由 hx-trigger 指定的事件)向最近的 WebSocket 发送消息。安装 ws 的最快方式是通过 CDN 加载。请记住,始终在扩展之前包含核心 htmx 库,并 启用扩展。
<head>
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.7/dist/htmx.min.js" integrity="sha384-ZBXiYtYQ6hJ2Y0ZNoYuI+Nq5MqWBr+chMrS/RkXpNzQCApHEhOt2aY8EJgqwHLkJ" 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-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>
WebSockets 扩展支持两个配置选项:
createWebSocket - 一个工厂函数,可用于创建自定义 WebSocket 实例。必须是一个函数,返回 WebSocket 对象wsBinaryType - 一个字符串值,用于定义套接字的 binaryType 属性。默认值为 blob上面的示例向 /chatroom 端点建立了一个 WebSocket 连接。从 WebSocket 发送下来的内容将被解析为 HTML,并根据 id 属性进行交换,使用与 Out of Band Swaps 相同的逻辑。
因此,如果您想更改交换方法(例如,将内容追加到元素末尾或将交换委托给扩展),您需要在服务器发送的消息正文中指定。
<!-- 默认将被解释为 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 而意外关闭,此扩展将尝试重连,直到连接重新建立。
默认情况下,扩展使用全抖动 exponential-backoff algorithm,该算法选择一个随机的重试延迟,随着时间指数增长。您可以通过将它写入 htmx.config.wsReconnectDelay 来使用不同的算法。此函数接受一个参数,即重试次数,并返回重试前等待的时间(以毫秒为单位)。
// 示例重连延迟(您不应该使用,因为它不如现有算法好)
htmx.config.wsReconnectDelay = function (retryCount) {
return retryCount * 1000 // 返回值以毫秒为单位
}
扩展还实现了一个简单的队列机制,在套接字不在 OPEN 状态时将消息保存在内存中,并在连接恢复时发送它们。
WebSockets 扩展暴露了一组事件,允许您观察和自定义其行为。
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 - 请求标头。如果不为 falsy,将附加到正文中的 HEADERS 属性detail.errors - 验证错误。如果不为空,将阻止发送并触发 htmx:validation:halted 事件detail.triggeringEvent - 触发发送的事件detail.messageBody - 将发送到套接字的原始消息正文。未定义,可以设置为 WebSockets 支持的任何类型的值。如果设置,将覆盖默认 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 编写的演示 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 服务器发送数据的子表单 |