> ## Documentation Index
> Fetch the complete documentation index at: https://bun.zhcndoc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 使用 Bun 的服务器发送事件（SSE）

[服务器发送事件](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) 允许您通过单个 HTTP 响应向浏览器推送一系列文本事件。客户端通过 [`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) 来接收这些事件。

在 Bun 中，您可以通过返回一个主体为流式来源的 `Response`，并将 `Content-Type` 头设置为 `text/event-stream` 来实现 SSE 端点。

<Note>
  `Bun.serve` 默认会在 **10 秒** 后关闭空闲连接。一个安静的 SSE 流会被视为空闲，因此下面的示例调用了 `server.timeout(req, 0)` 来禁用此流的超时。详情请参见
  [`idleTimeout`](/runtime/http/server#idletimeout)。
</Note>

## 使用异步生成器

在 Bun 中，`new Response` 直接接受一个异步生成器函数。这通常是编写 SSE 端点的最简单方法——每次 `yield` 会向客户端刷新一块数据，如果客户端断开连接，生成器的 `finally` 块会执行，从而可以清理资源。

```ts server.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
Bun.serve({
  port: 3000,
  routes: {
    "/events": (req, server) => {
      // SSE 流事件间通常比较安静。
      // 默认情况下，Bun.serve 会在 10 秒无活动后关闭连接。
      // 禁用该请求的空闲超时，以保持流无限期打开。
      server.timeout(req, 0);

      return new Response(
        async function* () {
          yield `data: connected at ${Date.now()}\n\n`;

          // 每 5 秒发送一个 tick，直到客户端断开连接。
          // 客户端断开时，生成器被返回（取消），此循环自动停止。
          while (true) {
            await Bun.sleep(5000);
            yield `data: tick ${Date.now()}\n\n`;
          }
        },
        {
          headers: {
            "Content-Type": "text/event-stream",
            "Cache-Control": "no-cache",
          },
        },
      );
    },
  },
});
```

## 使用 `ReadableStream`

如果您的事件来自回调——消息代理、定时器、外部推送——而不是线性的 `await` 流，`ReadableStream` 通常更合适。当客户端断开连接时，Bun 会自动调用流的 `cancel()` 方法，因此您可以在 `start()` 中设置的资源进行释放。

```ts server.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
Bun.serve({
  port: 3000,
  routes: {
    "/events": (req, server) => {
      server.timeout(req, 0);

      let timer: Timer;
      const stream = new ReadableStream({
        start(controller) {
          controller.enqueue(`data: connected at ${Date.now()}\n\n`);

          timer = setInterval(() => {
            controller.enqueue(`data: tick ${Date.now()}\n\n`);
          }, 5000);
        },
        cancel() {
          // 当客户端断开连接时自动调用。
          clearInterval(timer);
        },
      });

      return new Response(stream, {
        headers: {
          "Content-Type": "text/event-stream",
          "Cache-Control": "no-cache",
        },
      });
    },
  },
});
```
