FastAPI SSE本地正常但Azure Web App部署后无法工作求助
基于FastAPI搭建的SSE通知系统本地运行正常,但部署到Azure容器Web App后出现异常:服务器日志显示通知已发送并处理,但前端(Vue)无法接收。已尝试添加Cache-Control、X-Accel-Buffering请求头禁用响应缓冲,因采用容器部署未找到web.config等效配置。
路由示例代码:
@router.get( "/stream-notifs", response_description="User task notifications", response_model=Response, tags=["users"], ) async def notif_update_stream(request: Request, user_id: str): MESSAGE_STREAM_DELAY = 1 # second MESSAGE_STREAM_RETRY_TIMEOUT = 15000 # milisecond client_host = request.client.host print(f"Client {client_host} connected.") async def event_generator(): notif_q: asyncio.Queue = request.state.notif_q this_user_notifs = [] while True: notif_data: NotificationData = await notif_q.get() if notif_data.creator_id == UUID(user_id): # TODO: Add validation this_user_notifs.append(notif_data) print(f"Sending to: {request.client}") else: notif_q.put_nowait(notif_data) # If client was closed the connection if await request.is_disconnected(): break # Checks for new messages and return them to client if any for curr_notif in this_user_notifs: # Whenever a task is completed notif = Notification( id="message_id", event="completed_task", retry=MESSAGE_STREAM_RETRY_TIMEOUT, data=curr_notif, ).model_dump_json() yield notif this_user_notifs.pop() notif_q.task_done() print(f"Finished notif {notif}") await asyncio.sleep(MESSAGE_STREAM_DELAY) await notif_q.join() return EventSourceResponse( event_generator(), media_type="text/event-stream", headers={ "Cache-Control": "no-cache", "X-Accel-Buffering": "no", }, )
开启Azure Web App的WebSocket支持
登录Azure Portal,进入目标Web App的「配置」>「常规设置」,将WebSocket协议设置为「启用」。SSE依赖HTTP长连接,开启WebSocket后能让Azure代理层更好地兼容这类流式响应;同时确保「ARR Affinity」(应用请求路由亲和性)处于开启状态,保证同一客户端的请求始终路由到同一容器实例。补充长连接相关响应头
在EventSourceResponse的headers中添加Connection: keep-alive和Transfer-Encoding: chunked,明确告知代理层这是分块传输的长连接:return EventSourceResponse( event_generator(), media_type="text/event-stream", headers={ "Cache-Control": "no-cache", "X-Accel-Buffering": "no", "Connection": "keep-alive", "Transfer-Encoding": "chunked", }, )验证容器端口与网络配置
确认容器暴露的端口和Web App「配置」>「容器设置」中的「目标端口」一致(比如FastAPI默认的8000端口);检查Web App的「网络」配置,确保防火墙或VNet安全组没有阻止长连接流量。修正SSE输出格式
SSE要求每个事件必须以data:开头,结尾用两个换行符(\n\n)分隔。修改生成通知的代码,手动拼接符合规范的输出:notif_data = Notification( id=str(uuid.uuid4()), # 使用唯一ID避免重复处理 event="completed_task", retry=MESSAGE_STREAM_RETRY_TIMEOUT, data=curr_notif, ).model_dump_json() yield f"data: {notif_data}\n\n"配置前端与后端CORS
Vue前端初始化EventSource时,若跨域需开启withCredentials:const eventSource = new EventSource('/stream-notifs?user_id=' + userId, { withCredentials: true });后端FastAPI需配置CORS允许前端域名及凭证:
from fastapi.middleware.cors import CORSMiddleware app.add_middleware( CORSMiddleware, allow_origins=["你的前端域名"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )优化Azure Web App运行配置
在Web App「配置」>「常规设置」中开启「始终开启」,避免应用因空闲被回收;通过「监控」>「日志流」查看实时请求日志,确认响应头是否正确返回、请求是否被截断;用Application Insights监控请求状态码与响应时间,排查超时问题。
内容的提问来源于stack exchange,提问作者spook

