You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js API中如何转发Server-Sent Events(SSE)并维持稳定连接

Next.js API转发SSE事件流:客户端接收与连接清理问题解决

我用Next.js API作为中间层,转发需要Bearer认证的后端SSE事件流到客户端,遇到两个核心问题:

  • 初始状态下客户端无法接收事件,添加no-cache, no-transform到Cache-Control后可接收,但客户端断开连接时,服务端与后端的SSE连接仍未关闭
  • 若在API中调用res.end(),客户端能收到事件,但连接会立即关闭并触发每秒重连

问题1:客户端无法接收事件(已解决,需巩固配置)

确保SSE响应头配置完整,除已设置的项外,显式添加Transfer-Encoding: chunked保证分块传输,同时Cache-Control设为no-cache, no-transform避免代理或缓存拦截事件流。

问题2:客户端断开后服务端连接未关闭

核心是监听客户端请求的close和error事件,当客户端断开时主动关闭与后端的EventSource连接,避免资源泄漏。绝对不要在正常转发事件时调用res.end(),否则会直接终止响应,触发客户端SSE自动重连。


修改后的完整API代码(/api/events/index.js)

import EventSource from 'eventsource';
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';

export default withApiAuthRequired(async function handler(req, res) {
  if (req.method !== 'GET') {
    res.status(405).end('Method Not Allowed');
    return;
  }

  const { accessToken } = await getAccessToken(req, res);

  // 配置标准SSE响应头
  res.writeHead(200, {
    'Connection': 'keep-alive',
    'Cache-Control': 'no-cache, no-transform',
    'Content-Type': 'text/event-stream',
    'Transfer-Encoding': 'chunked',
  });

  // 建立与后端的SSE连接
  const eventSource = new EventSource(
    `http://localhost:8000/v1/event-stream`,
    { headers: { Authorization: `Bearer ${accessToken}` } },
  );

  // 转发后端事件到客户端
  eventSource.onmessage = (e) => {
    res.write(`data: ${e.data}\n\n`);
    // 手动刷新缓冲区,确保事件即时发送
    if (res.flush) res.flush();
  };

  // 处理后端SSE连接错误
  eventSource.onerror = (error) => {
    console.error('后端SSE连接异常:', error);
    res.write(`event: error\ndata: ${JSON.stringify({ message: '后端事件流断开' })}\n\n`);
    if (res.flush) res.flush();
    eventSource.close();
    res.end(); // 后端异常时主动结束客户端响应
  };

  // 客户端断开时清理后端连接
  const cleanupConnection = () => {
    console.log('客户端断开,清理后端SSE连接');
    eventSource.close();
    res.end();
  };

  req.on('close', cleanupConnection);
  req.on('error', cleanupConnection);
});

客户端代码优化建议

const IndexPage = () => {
  useEffect(() => {
    const eventSource = new EventSource(`/api/events`); // 使用相对路径适配不同环境

    eventSource.onmessage = (e) => {
      console.log('收到事件:', e.data);
    };

    eventSource.onerror = (error) => {
      console.error('SSE连接错误:', error);
      eventSource.close(); // 错误时主动关闭,避免无效重连
    };

    return () => {
      eventSource.close();
    };
  }, []);

  return <div>监听SSE事件...</div>;
};

export default IndexPage;

关键注意事项

  • 禁止在正常事件转发流程中调用res.end(),仅在后端连接异常或客户端断开时使用
  • 部分Node.js/Next.js版本中,res.write()后需调用res.flush()确保数据即时发送到客户端
  • 必须监听客户端请求的close/error事件,及时清理后端SSE连接,防止资源泄漏

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 10:05:22