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
相关产品推荐
相关产品推荐

