htmx 服务器发送事件 (SSE) 扩展

Server Sent Events 扩展直接从 HTML 连接到 EventSource。它管理与 Web 服务器的连接,监听服务器事件,然后实时将事件内容替换到您的 htmx 网页中。

SSE 是一种轻量级的 WebSockets 替代方案,它通过现有的 HTTP 连接工作,因此易于通过代理服务器和防火墙使用。请记住,SSE 是一种单向服务,因此一旦建立连接,您就无法向 SSE 服务器发送任何消息。如果您需要双向通信,则应考虑使用 WebSockets

此扩展替换了 htmx 以前版本中内置的实验性 hx-sse 属性。有关从旧版本迁移的帮助,请参阅本页面底部的迁移指南。

使用以下属性配置 SSE 连接的行为

安装


<script src="https://unpkg.com/[email protected]/sse.js"></script>

使用


<div hx-ext="sse" sse-connect="/chatroom" sse-swap="message">
    Contents of this box will be updated in real time
    with every SSE message received from the chatroom.
</div>

连接到 SSE 服务器

要连接到 SSE 服务器,请使用 hx-ext="sse" 属性在该 HTML 元素上安装扩展,然后在元素中添加 sse-connect="<url>" 建立连接。

在设计您的服务器应用程序时,请记住 SSE 的工作原理与任何 HTTP 请求相同。虽然您在建立连接后无法向服务器发送任何消息,但您可以在请求中将参数与您的请求一起发送到服务器。因此,您不是在 https://my-server/chat-updates 上建立到服务器的 SSE 连接,也可以连接到 https://my-server/chat-updates?friends=true&format=detailed。这允许您的服务器根据客户端的需要自定义其响应。

接收命名事件

SSE 消息由事件名称和数据包组成。消息中不允许其他元数据。以下是一个示例

event: EventName
data: <div>Content to swap into your HTML page.</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>Content to swap into your HTML page.</div>

<div hx-ext="sse" sse-connect="/event-source" sse-swap="message"></div>

接收多个事件

您还可以从单个 EventSource 监听多个事件(命名或未命名)。监听器必须是 1)包含 hx-extsse-connect 属性的同一个元素,或 2)包含 hx-extsse-connect 属性的元素的子元素。


Multiple events in the same element
<div hx-ext="sse" sse-connect="/server-url" sse-swap="event1,event2"></div>

Multiple events in different elements (from the same source).
<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 Event Stream 意外关闭,浏览器应该尝试自动重新连接。但是,在极少数情况下,这不起作用,并且您的浏览器可能会挂起。此扩展在浏览器自动重新连接的基础上添加了自己的重新连接逻辑(使用 指数退避算法),因此您的 SSE 流始终尽可能可靠。

使用演示服务器测试 SSE 连接

Htmx 包含一个用 Node.js 编写的演示 SSE 服务器,它将帮助您查看 SSE 的实际操作,并开始引导您自己的 SSE 代码。它位于 htmx 分发版的 /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>"在标签中添加一个新属性 sse-connect,该属性指定 Event Stream 的 URL。此属性必须与 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) {
    // do something before the event data is swapped in
})

每个事件对象都有一个 detail 字段,其中包含事件的详细信息。

htmx:sseOpen

当 SSE 连接成功建立时,将分发此事件。

详细信息

htmx:sseError

当 SSE 连接无法建立时,将分发此事件。

详细信息

htmx:sseBeforeMessage

在将 SSE 事件数据替换到 DOM 中之前,将分发此事件。如果您不想替换,请对事件调用 preventDefault()。此外,detail 字段是一个 MessageEvent - 这是 EventSource 在收到 SSE 消息时创建的事件。

详细信息

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":
            // Parent node is missing and therefore connection was closed
        ...
        case "nodeReplaced":
            // Parent node replacement caused closing of connection
        ...
        case "message":
            // connection was closed due to reception of message sse-close
        ...
    }
})
详细信息

其他 SSE 资源