You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Cloudflare Workers中实现SSE?现有方案返回响应后即终止

在Cloudflare Workers中正确实现Server-Sent Events(SSE)

我懂你碰到的问题——Cloudflare Workers的运行模型和普通服务器不一样,你的代码之所以返回响应后立刻终止,是因为两个关键错误:

  1. 错误设置了响应状态码101:这是用于协议切换(比如WebSocket)的,SSE本质是普通的HTTP长连接,应该用200状态码。
  2. 没有把定时任务和Worker的生命周期绑定:Cloudflare Workers在返回响应后,如果没有活跃的异步任务或流操作,会立即终止进程,你的setInterval根本没机会持续运行。

修正后的完整实现

下面是可以稳定运行的SSE代码,我会一步步解释关键点:

export default {
  async fetch(request) {
    // 处理OPTIONS预检请求(如果需要跨域)
    if (request.method === 'OPTIONS') {
      return new Response(null, {
        headers: {
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Methods': 'GET,OPTIONS',
          'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',
        },
      });
    }

    // 创建AbortController监听客户端断开连接,及时清理资源
    const controller = new AbortController();
    const { signal } = controller;

    // 创建可读流,用于推送SSE事件
    const stream = new ReadableStream({
      start(controller) {
        // 定时器每隔5秒推送一次消息
        const intervalId = setInterval(() => {
          try {
            // SSE格式必须严格:data: 内容\n\n
            const message = `data: Hello from Cloudflare Workers at ${new Date().toISOString()}\n\n`;
            controller.enqueue(new TextEncoder().encode(message));
          } catch (err) {
            // 如果客户端断开,会抛出错误,清理定时器
            clearInterval(intervalId);
            controller.error(err);
          }
        }, 5000);

        // 客户端断开连接时触发,清理定时器
        signal.addEventListener('abort', () => {
          clearInterval(intervalId);
          controller.close();
        });
      },
      // 当客户端暂停接收时触发,可以暂停推送
      pull(controller) {
        // 这里可以根据需要处理暂停逻辑,比如缓存消息
      },
      cancel() {
        // 流被取消时清理资源
        console.log('SSE connection closed by client');
      },
    });

    // 设置正确的响应头
    const headers = new Headers({
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache, no-transform',
      'Connection': 'keep-alive',
      'Access-Control-Allow-Origin': '*',
      // 告诉Cloudflare不要缓存响应,保持长连接
      'CF-Cache-Status': 'DYNAMIC',
    });

    // 返回200状态码的响应,绑定AbortController的signal
    return new Response(stream, {
      status: 200,
      headers,
      signal,
    });
  },
};

关键细节说明

  • 状态码与响应头:必须用200状态码,同时设置CF-Cache-Status: DYNAMIC避免Cloudflare缓存或中断长连接。
  • AbortController:用来监听客户端断开事件,及时清理定时器,避免Worker资源泄漏。
  • ReadableStream的生命周期:通过controller.enqueue推送消息,流会保持连接直到客户端断开或主动关闭,这样Worker进程会一直保持活跃直到连接结束。
  • 跨域处理:添加了OPTIONS预检请求的处理,根据你的实际需求调整Access-Control-Allow-Origin的值。

为什么你的原始代码不行?

  • status: 101是错误的,SSE不需要切换协议,用普通HTTP响应即可。
  • 你创建的TransformStream没有和Worker的生命周期绑定,返回响应后Worker进程被立即终止,setInterval根本无法持续执行。

Cloudflare Workers的限制注意

  • 免费计划的Worker长连接最长维持时间为10分钟,付费计划可以延长。
  • 不要在SSE连接中执行密集计算,避免触发Worker的资源限制。

内容的提问来源于stack exchange,提问作者Tector

火山引擎 最新活动