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

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,提问作者Артём Малов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 04:40:00