htmx Web Socket 扩展

Web Sockets 扩展实现了从 HTML 直接与 Web Sockets 服务器进行简单、双向通信的功能。这取代了 htmx 之前版本中内置的实验性 hx-ws 属性。有关从旧版本迁移的帮助,请参阅本页底部的 Migrating 指南。

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

安装

安装 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):

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 扩展支持两个配置选项:

从 WebSocket 接收消息

上面的示例向 /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>

向 WebSocket 发送消息

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

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

自动重连

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

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

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

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

事件

WebSockets 扩展暴露了一组事件,允许您观察和自定义其行为。

事件 - 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 编写的演示 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 服务器发送数据的子表单