Server Sent Events 扩展直接从 HTML 连接到 EventSource。它管理与您的 Web 服务器的连接,监听服务器事件,然后实时将它们的内容交换到您的 htmx 网页中。
SSE 是 WebSockets 的轻量级替代方案,它通过现有的 HTTP 连接工作,因此通过代理服务器和防火墙使用起来很容易。请记住,SSE 是一种单向服务,一旦连接建立,您就无法向 SSE 服务器发送任何消息。如果您需要双向通信,则应考虑使用 WebSockets。
此扩展替换了 htmx 之前版本中内置的实验性 hx-sse 属性。有关从旧版本迁移的帮助,请参阅本页底部的迁移指南。
使用以下属性来配置 SSE 连接的行为:
sse-connect="<url>" - SSE 服务器的 URL。sse-swap="<message-name>" - 要交换到 DOM 中的消息名称。hx-trigger="sse:<message-name>" - SSE 消息也可以使用 hx-trigger 属性触发 HTTP 回调。sse-close=<message-name> - 当收到该消息时,优雅地关闭 EventStream。这可能有助于向最终将停止的客户端发送信息。安装 sse 的最快方式是通过 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-sse@2.2.2" integrity="sha384-Y4gc0CK6Kg+hmulDc6rZPJu0tqvk7EWlih0Oh+2OkAi1ZDlCbBDCQEE2uVk472Ky" crossorigin="anonymous"></script>
</head>
<body hx-ext="sse">
未压缩版本也可从 https://cdn.jsdelivr.net/npm/htmx-ext-sse/dist/sse.js 获取。
虽然 CDN 方法简单,但您可能需要考虑在生产环境中不使用 CDN。安装 sse 的下一个最简单方法是将它复制到您的项目中。从 https://cdn.jsdelivr.net/npm/htmx-ext-sse 下载扩展,将其添加到项目中的适当目录,并在需要的地方使用 <script> 标签包含它。
对于 npm 风格的构建系统,您可以通过 npm 安装 sse:
npm install htmx-ext-sse
安装后,您需要使用适当的工具将 node_modules/htmx-ext-sse/dist/sse.js(或 .min.js)打包。例如,您可以将扩展与来自 node_modules/htmx.org/dist/htmx.js 的 htmx 核心以及项目特定代码打包在一起。
如果您使用打包器管理 JavaScript(例如 Webpack、Rollup):
htmx.org 和 htmx-ext-sseindex.jsimport `htmx.org`;
import `htmx-ext-sse`;
<div hx-ext="sse" sse-connect="/chatroom" sse-swap="message">
此框的内容将随着从聊天室接收到的每个 SSE 消息实时更新。
</div>
要连接到 SSE 服务器,请使用 hx-ext="sse" 属性将扩展安装到该 HTML 元素上,然后向元素添加 sse-connect="<url>" 来建立连接。
在设计服务器应用程序时,请记住 SSE 就像任何 HTTP 请求一样工作。虽然在建立连接后您无法向服务器发送任何消息,但您可以与请求一起向服务器发送参数。因此,您可以连接到 https://my-server/chat-updates?friends=true&format=detailed,而不是仅连接到服务器上的 https://my-server/chat-updates。这允许您的服务器根据客户端需求自定义其响应。
SSE 消息由事件名称和数据包组成。消息中不允许其他元数据。以下是一个示例:
event: EventName
data: <div>要交换到 HTML 页面的内容。</div>
我们将使用 sse-swap 属性来监听此事件,并将其内容交换到我们的网页中。
<div hx-ext="sse" sse-connect="/event-source" sse-swap="EventName"></div>
请注意,服务器消息中的名称 EventName 必须与 sse-swap 属性中的值匹配。您的服务器可以使用任意多个不同的事件名称,但要小心:浏览器只能监听明确命名的那些事件。因此,如果您的服务器发送了一个名为 ChatroomUpdate 的事件,但您的浏览器仅监听名为 ChatUpdate 的事件,那么多余的事件将被丢弃。
SSE 消息也可以不带任何事件名称发送。在这种情况下,浏览器使用默认名称 message 作为替代。上述规则仍然适用。如果您的服务器发送了一个未命名消息,那么您必须通过包含 sse-swap="message" 来监听它。没有使用通配符名称的选项。以下是其外观:
data: <div>要交换到 HTML 页面的内容。</div>
<div hx-ext="sse" sse-connect="/event-source" sse-swap="message"></div>
您也可以从单个 EventSource 监听多个事件(命名或未命名)。监听器必须是 1) 包含 hx-ext 和 sse-connect 属性的同一元素,或 2) 包含 hx-ext 和 sse-connect 属性的元素的子元素。
同一元素中的多个事件
<div hx-ext="sse" sse-connect="/server-url" sse-swap="event1,event2"></div>
来自同一源的不同元素中的多个事件。
<div hx-ext="sse" sse-connect="/server-url">
<div sse-swap="event1"></div>
<div sse-swap="event2"></div>
</div>
建立服务器发送事件连接后,子元素可以通过使用特殊的 hx-trigger 语法 sse:<event_name> 来监听这些事件。当与 hx-get 或类似属性结合使用时,这将触发元素发出请求。
以下是一个示例:
<div hx-ext="sse" sse-connect="/event_stream">
<div hx-get="/chatroom" hx-trigger="sse:chatter">
...
</div>
</div>
此示例建立与 event_stream 端点的 SSE 连接,每当看到 chatter 事件时,就会触发对 /chatroom URL 的 GET 请求。
如果 SSE 事件流意外关闭,浏览器应该尝试自动重连。然而,在极少数情况下,这不起作用,您的浏览器可能会挂起。此扩展在其上添加了自己的重连逻辑(使用指数退避算法),以确保您的 SSE 流始终尽可能可靠。
Htmx 包含一个用 Node.js 编写的演示 SSE 服务器,它将帮助您看到 SSE 的实际效果,并开始为您的 SSE 代码打下基础。它位于 htmx-extensions 仓库的 /test/ws-sse 文件夹中。请参阅 /test/ws-sse/README.md 以获取运行和使用测试服务器的说明。
htmx 的之前版本使用内置标签 hx-sse 来实现服务器发送事件。此代码已迁移到扩展中。以下是迁移到此版本的步骤:
| 旧属性 | 新属性 | 注释 |
|---|---|---|
hx-sse="" | hx-ext="sse" | 使用 hx-ext="sse" 属性将 SSE 扩展安装到任何 HTML 元素中。 |
hx-sse="connect:<url>" | sse-connect="<url>" | 向指定事件流 URL 的标签添加新属性 sse-connect。此属性必须与 hx-ext 属性位于同一标签中。 |
hx-sse="swap:<EventName>" | sse-swap="<EventName>" | 向通过 SSE 扩展交换的任何元素添加新属性 sse-swap。此属性必须放置在包含 hx-ext 属性的标签上或内部。 |
hx-trigger="sse:<EventName>" | 无更改 | 任何 hx-trigger 属性无需更改。扩展将识别这些属性并为任何以 sse: 开头的事件添加监听器。 |
此扩展分发多个事件。您可以像这样监听这些事件:
document.body.addEventListener('htmx:sseBeforeMessage', function (e) {
// 在事件数据交换之前执行某些操作
})
每个事件对象都有一个 detail 字段,包含事件细节。
htmx:sseOpen当 SSE 连接成功建立时,会分发此事件。
detail.elt - 设置 SSE 连接的元素。这是具有 sse-connect 属性的元素。detail.source - EventSource 对象。htmx:sseError当无法建立 SSE 连接时,会分发此事件。
detail.error - 在创建 EventSource 时发生错误。detail.source - EventSource。htmx:sseBeforeMessage在 SSE 事件数据交换到 DOM 之前立即分发此事件。如果您不想交换,请在事件上调用 preventDefault()。此外,detail 字段是一个 MessageEvent - 这是 EventSource 在接收 SSE 消息时创建的事件。
detail.elt - 交换目标。htmx:sseMessage在 SSE 事件数据交换到 DOM 之后分发此事件。detail 字段是一个 MessageEvent - 这是 EventSource 在接收 SSE 消息时创建的事件。
htmx:sseClose此事件在三种不同的关闭场景中分发。为了控制场景,用户可以控制 evt.detail.sseclose 属性。
document.body.addEventListener('htmx:sseClose', function (e) {
const reason = e.detail.type
switch (reason) {
case "nodeMissing":
// 父节点缺失,因此连接关闭
...
case "nodeReplaced":
// 父节点替换导致连接关闭
...
case "message":
// 由于接收到 sse-close 消息而关闭连接
...
}
})
detail.elt - 交换目标。