useEffect(() => { const eventSource = new EventSource('/api/demo/push'); const handler = (event: MessageEvent<any>) => { let data = JSON.parse(event.data) as DemoData // 业务逻辑 ... } eventSource.addEventListener("DEMO_EVENT", handler); return () => { eventSource.removeEventListener("DEMO_EVENT", handler); } }, [])
做事端
做事真个话最关键便是要把数据封装成事宜流,SSE中支持的协议是GET要求,通报参数的话有些麻烦,可以通报路径参数,歪哥这里暂时不须要。
下面是大略示例,这里每一秒钟向客户端推送一条数据
export async function GET(req: Request) { let responseStream = new TransformStream(); const writer = responseStream.writable.getWriter(); const encoder = new TextEncoder(); let eventId = 0; const intervalId = setInterval(async () => { const data = await getDataFromDB(); const eventData = JSON.stringify(data); const eventName = "DEMO_EVENT"; writer.write(encoder.encode(`event: ${eventName}\n`)); writer.write(encoder.encode(`id: ${eventId}\n`)); writer.write(encoder.encode(`data: ${eventData}\n\n`)); eventId++; if (eventId >= 3600) { clearInterval(intervalId); writer.close(); } }, 1000); return new Response(responseStream.readable, { headers: { "Content-Type": "text/event-stream", "Connection": "keep-alive", "Cache-Control": "no-cache, no-transform", }, });}
例子中有一个定时器,如果里面须要读取数据库或网络数据的话,记得加异步关键字async,然后数据流就按照SSE的数据格式,写好id、event、data就行啦。最后记得设置header,紧张是content-type。
这里面歪哥为了防止涌现非常导致推送没有精确停滞,设置了最长推送一个小时就关闭流,可能不须要或者有更好的方法,这个看大家实际情形了。
总结歪哥之前用WebSocket比较多,SSE用的少,故意思的是,最近很火的大模型对话中,AI天生回答的底层传输协议也是大量利用SSE,包括ChatGPT这种。
想想也是有道理,大模型回答本来便是一个个token的天生,并不是一下子把一段回答文本都放出来,天然便是这种推送的机制,SSE比较轻量,这种做事端向客户端单向推送场景利用再得当不过了,以是大家还是有必要理解一下的。