FastAPI SSE多客户端响应拆分问题求助
问题分析与解决
你的问题出在共享的event_list被直接修改上:每次客户端连接后,生成器里用event_list.pop()移除元素,当多个客户端同时连接时,它们会争抢列表里的事件,导致每个客户端只能拿到一部分(比如A拿第一个、B拿第二个,看起来各收一半)。这不是本地测试的问题,是代码逻辑的bug。
另外还有两个小问题:
- 响应头设置放在生成器里无效,因为响应头在返回
EventSourceResponse时就已经发送了,生成器运行时头信息已经确定。 - 循环
for i in range(len(event_list))配合pop()会导致遍历不完整,因为每次pop都会让列表长度动态变化。
修正后的代码
@socket_router.get('/stream') async def message_stream(request: Request): # 提前设置SSE响应头,EventSourceResponse会自动处理部分字段,也可显式指定 headers = { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", "Connection": "keep-alive" } async def event_generator(): while True: if await request.is_disconnected(): print('disconnected') break # 先复制当前事件列表,再清空原列表,避免多客户端争抢事件 current_events = event_list.copy() if current_events: # 清空原列表,防止后续轮询重复发送相同事件 event_list.clear() for sending_message in current_events: yield { "event": 'message', "id": sending_message.id, "retry": sending_message.retry, "data": sending_message.data } await asyncio.sleep(5) return EventSourceResponse(event_generator(), headers=headers)
关键修改点
- 复制事件列表:用
event_list.copy()创建当前事件的副本,确保所有连接的客户端都能拿到完整的事件集合,不会互相干扰。 - 清空原列表:复制完成后清空
event_list,避免后续轮询时重复发送已处理的事件。 - 响应头提前设置:在返回
EventSourceResponse时传入headers,确保头信息在响应建立时就正确发送。 - 遍历副本列表:直接遍历复制后的列表,避免修改原列表导致的遍历异常。
这样修改后,所有连接的客户端都会收到完整的事件内容,实现同步更新的效果。
内容的提问来源于stack exchange,提问作者Артём Малов
相关产品推荐
相关产品推荐

