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

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

¥The Server Sent Events extension connects to an EventSource directly from HTML. It manages the connections to your web server, listens for server events, and then swaps their contents into your htmx webpage in real-time.

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

¥SSE is a lightweight alternative to WebSockets that works over existing HTTP connections, so it is easy to use through proxy servers and firewalls. Remember, SSE is a uni-directional service, so you cannot send any messages to an SSE server once the connection has been established. If you need bi-directional communication, then you should consider using WebSockets instead.

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

¥This extension replaces the experimental hx-sse attribute built into previous versions of htmx. For help migrating from older versions, see the migration guide at the bottom of this page.

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

¥Use the following attributes to configure how SSE connections behave:

安装

¥Installing

安装 sse 的最快方法是通过 CDN 加载它。请记住始终在扩展和 启用扩展 之前包含核心 htmx 库。

¥The fastest way to install sse is to load it via a CDN. Remember to always include the core htmx library before the extension and enable the extension.

<head>
    <script src="https://unpkg.com/htmx.org@2.0.4" integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+" crossorigin="anonymous"></script>
    <script src="https://unpkg.com/htmx-ext-sse@2.2.2" integrity="sha384-Y4gc0CK6Kg+hmulDc6rZPJu0tqvk7EWlih0Oh+2OkAi1ZDlCbBDCQEE2uVk472Ky" crossorigin="anonymous"></script>
</head>
<body hx-ext="sse">

https://unpkg.com/htmx-ext-sse/dist/sse.js 上还有一个未缩小的版本。

¥An unminified version is also available at https://unpkg.com/htmx-ext-sse/dist/sse.js.

虽然 CDN 方法很简单,但你可能需要考虑 在生产中不使用 CDN。安装 sse 的下一个最简单的方法是将其复制到你的项目中。从 https://unpkg.com/htmx-ext-sse 下载扩展,将其添加到项目中的相应目录中,并在必要时使用 <script> 标签将其包含在内。

¥While the CDN approach is simple, you may want to consider not using CDNs in production. The next easiest way to install sse is to simply copy it into your project. Download the extension from https://unpkg.com/htmx-ext-sse, add it to the appropriate directory in your project and include it where necessary with a <script> tag.

对于 npm 样式的构建系统,你可以通过 npm 安装 sse

¥For npm-style build systems, you can install sse via npm:

npm install htmx-ext-sse

安装后,你需要使用适当的工具来打包 node_modules/htmx-ext-sse/dist/sse.js(或 .min.js)。例如,你可以将扩展与来自 node_modules/htmx.org/dist/htmx.js 的 htmx 核心和项目特定代码打包在一起。

¥After installing, you’ll need to use appropriate tooling to bundle node_modules/htmx-ext-sse/dist/sse.js (or .min.js). For example, you might bundle the extension with htmx core from node_modules/htmx.org/dist/htmx.js and project-specific code.

如果你使用打包器来管理你的 javascript(例如 Webpack、Rollup):

¥If you are using a bundler to manage your javascript (e.g. Webpack, Rollup):

import `htmx.org`;
import `htmx-ext-sse`; 

使用

¥Usage


<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 服务器

¥Connecting to an SSE Server

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

¥To connect to an SSE server, use the hx-ext="sse" attribute to install the extension on that HTML element, then add sse-connect="<url>" to the element to make the connection.

在设计服务器应用时,请记住 SSE 的工作方式与任何 HTTP 请求一样。虽然建立连接后你无法向服务器发送任何消息,但你可以将参数与请求一起发送到服务器。因此,除了在 https://my-server/chat-updates 处与你的服务器建立 SSE 连接之外,你还可以连接到 https://my-server/chat-updates?friends=true&format=detailed。这允许你的服务器根据客户端的需求定制其响应。

¥When designing your server application, remember that SSE works just like any HTTP request. Although you cannot send any messages to the server after you have established a connection, you can send parameters to the server along with your request. So, instead of making an SSE connection to your server at https://my-server/chat-updates you can also connect to https://my-server/chat-updates?friends=true&format=detailed. This allows your server to customize its responses to what your client needs.

接收命名事件

¥Receiving Named Events

SSE 消息由事件名称和数据包组成。消息中不允许有其他元数据。这是一个例子:

¥SSE messages consist of an event name and a data packet. No other metadata is allowed in the message. Here is an example:

event: EventName
data: <div>Content to swap into your HTML page.</div>

我们将使用 sse-swap 属性来监听此事件并将其内容交换到我们的网页中。

¥We’ll use the sse-swap attribute to listen for this event and swap its contents into our webpage.


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

请注意,服务器消息中的名称 EventName 必须与 sse-swap 属性中的值匹配。你的服务器可以根据需要使用任意数量的不同事件名称,但要小心:浏览器只能监听已明确命名的事件。因此,如果你的服务器发送了名为 ChatroomUpdate 的事件,但你的浏览器只监听名为 ChatUpdate 的事件,则额外的事件将被丢弃。

¥Notice that the name EventName from the server’s message must match the value in the sse-swap attribute. Your server can use as many different event names as necessary, but be careful: browsers can only listen for events that have been explicitly named. So, if your server sends an event named ChatroomUpdate but your browser is only listening for events named ChatUpdate then the extra event will be discarded.

接收未命名事件

¥Receiving Unnamed Events

SSE 消息也可以在没有任何事件名称的情况下发送。在这种情况下,浏览器将使用默认名称 message 代替。上面指定的相同规则仍然适用。如果你的服务器发送了一条未命名的消息,那么你必须通过包含 sse-swap="message" 来监听它。没有使用万能名称的选项。这是它的样子:

¥SSE messages can also be sent without any event name. In this case, the browser uses the default name message in its place. The same rules specified above still apply. If your server sends an unnamed message, then you must listen for it by including sse-swap="message". There is no option for using a catch-all name. Here’s how this looks:

data: <div>Content to swap into your HTML page.</div>

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

接收多个事件

¥Receiving Multiple Events

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

¥You can also listen to multiple events (named or unnamed) from a single EventSource. Listeners must be either 1) the same element that contains the hx-ext and sse-connect attributes, or 2) child elements of the element containing the hx-ext and sse-connect attributes.


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>

触发服务器回调

¥Trigger Server Callbacks

当建立了服务器发送事件的连接时,子元素可以使用特殊的 hx-trigger 语法 sse:<event_name> 来监听这些事件。当与 hx-get 或类似事件结合使用时,将触发元素发出请求。

¥When a connection for server sent events has been established, child elements can listen for these events by using the special hx-trigger syntax sse:<event_name>. This, when combined with an hx-get or similar will trigger the element to make a request.

这是一个例子:

¥Here is an example:


<div hx-ext="sse" sse-connect="/event_stream">
    <div hx-get="/chatroom" hx-trigger="sse:chatter">
        ...
    </div>
</div>

此示例建立了与 event_stream 端点的 SSE 连接,然后每当看到 chatter 事件时,就会触发 GET/chatroom url。

¥This example establishes an SSE connection to the event_stream end point which then triggers a GET to the /chatroom url whenever the chatter event is seen.

自动重新连接

¥Automatic Reconnection

如果 SSE 事件流意外关闭,浏览器应该尝试自动重新连接。但是,在极少数情况下,这不起作用,你的浏览器可能会挂起。此扩展在浏览器的自动重新连接之上添加了自己的重新连接逻辑(使用 指数退避算法),以便你的 SSE 流始终尽可能可靠。

¥If the SSE Event Stream is closed unexpectedly, browsers are supposed to attempt to reconnect automatically. However, in rare situations this does not work and your browser can be left hanging. This extension adds its own reconnection logic (using an exponential-backoff algorithm) on top of the browser’s automatic reconnection, so that your SSE streams will always be as reliable as possible.

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

¥Testing SSE Connections with the Demo Server

Htmx 包含一个用 Node.js 编写的演示 SSE 服务器,可帮助你查看 SSE 的运行情况,并开始引导你自己的 SSE 代码。它位于 htmx-extensions 存储库的 /test/ws-sse 文件夹中。查看 /test/ws-sse/README.md 以获取有关运行和使用测试服务器的说明。

¥Htmx includes a demo SSE server written in Node.js that will help you to see SSE in action, and begin bootstrapping your own SSE code. It is located in the /test/ws-sse folder of the htmx-extensions repository. Look at /test/ws-sse/README.md for instructions on running and using the test server.

从以前的版本迁移

¥Migrating from Previous Versions

以前版本的 htmx 使用内置标记 hx-sse 来实现服务器发送事件。此代码已迁移到扩展中。以下是迁移到此版本所需采取的步骤:

¥Previous versions of htmx used a built-in tag hx-sse to implement Server Sent Events. This code has been migrated into an extension instead. Here are the steps you need to take to migrate to this version:

旧属性新属性评论
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>"NO CHANGE任何 hx-trigger 属性都不需要更改。扩展将识别这些属性并为任何以 sse: 为前缀的事件添加监听器

监听此扩展发送的事件

¥Listening to events dispatched by this extension

此扩展分派多个事件。你可以像这样监听这些事件:

¥This extension dispatches several events. You can listen for these events like so:

document.body.addEventListener('htmx:sseBeforeMessage', function (e) {
    // do something before the event data is swapped in
})

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

¥Each event object has a detail field that contains details of the event.

htmx:sseOpen

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

¥This event is dispatched when an SSE connection has been successfully established.

详细信息

¥Details

htmx:sseError

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

¥This event is dispatched when an SSE connection could not be established.

详细信息

¥Details

htmx:sseBeforeMessage

此事件在 SSE 事件数据交换到 DOM 之前分派。如果你不想交换,请在事件上调用 preventDefault()。此外,detail 字段是 MessageEvent - 这是 EventSource 收到 SSE 消息时创建的事件。

¥This event is dispatched just before the SSE event data is swapped into the DOM. If you don’t want to swap call preventDefault() on the event. Additionally the detail field is a MessageEvent - this is the event created by EventSource when it receives an SSE message.

详细信息

¥Details

htmx:sseMessage

此事件在 SSE 事件数据交换到 DOM 后分派。detail 字段是 MessageEvent - 这是 EventSource 收到 SSE 消息时创建的事件。

¥This event is dispatched after the SSE event data has been swapped into the DOM. The detail field is a MessageEvent - this is the event created by EventSource when it receives an SSE message.

htmx:sseClose

此事件在三种不同的关闭场景中分派。要控制用户可以控制 evt.detail.sseclose 属性的场景。

¥This event is dispatched in three different closing scenario. To control for the scenario the user can control for the evt.detail.sseclose property.

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
        ...
    }
})

详细信息

¥Details

其他 SSE 资源

¥Additional SSE Resources