Socket实时推送问题:FastApi建立WebSocket连接后无法接收Http请求求助
问题分析与方案解答
现有方案可行性说明
你这套技术架构(Python脚本发HTTP请求到FastAPI服务端,再通过WebSocket推送给Angular前端)本身是完全可行的,当前问题是服务端和脚本的代码写法错误导致的功能异常,和架构逻辑无关。
问题根因
- 服务端使用了同步阻塞的
queue.Queue,在异步WebSocket函数中调用queue.get()时,会直接卡住整个asyncio事件循环,期间所有HTTP请求都无法被调度处理。 - WebSocket的异步循环中没有主动让出事件循环的逻辑,死循环会长期占用执行权,导致其他请求抢不到资源。
PUT /dummy接口的参数定义错误,你要接收JSON请求体,但直接声明dummy参数会被FastAPI识别为查询参数,无法正确接收提交的JSON数据。- Python脚本中
requests.put用data参数传递字典,会发送application/x-www-form-urlencoded格式的请求,和手动设置的Content-Type: application/json不匹配,请求本身就不符合接口要求。
修复后的代码
服务端 myserver.py
import asyncio from fastapi import FastAPI, WebSocket, Body from starlette.middleware.cors import CORSMiddleware import uvicorn # 替换为asyncio异步队列,不会阻塞事件循环 queue = asyncio.Queue() app = FastAPI() app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], expose_headers=["*"]) @app.websocket("/ws") async def websocket_endpoint(websocket: WebSocket): await websocket.accept() while True: # 异步get,队列空时自动让出事件循环,不阻塞其他请求 msg = await queue.get() await websocket.send_json(data=msg) queue.task_done() @app.put("/dummy") async def update(dummy = Body(embed=True)): await queue.put(dummy) return {"status": "success"} if __name__ == "__main__": uvicorn.run("myserver:app", host='0.0.0.0', port=8000)
数据脚本 script.py
import requests import time if __name__ == "__main__": while True: url = "http://localhost:8000/dummy" # 用json参数自动设置正确的请求头,无需手动配置Content-Type requests.put(url, json={"dummy": "OK"}) time.sleep(1)
可替代方案及适用场景
- Python脚本直接通过WebSocket和服务端通讯
原因:省略HTTP接口层,通讯延迟更低,实现更简单,适合单脚本高频推送实时数据的场景。 - 引入消息中间件做中转
原因:如果后续需要多数据源推送、多服务端实例部署、消息持久化、削峰填谷的需求,用Redis Pub/Sub、RabbitMQ等中间件做消息中转,稳定性和扩展性远高于服务端本地队列。 - 用SSE(服务端推送事件)替代WebSocket给前端推数据
原因:如果只有服务端到前端的单向数据推送需求,SSE比WebSocket更轻量,原生支持断线自动重连,前端和服务端的实现成本都更低。
内容的提问来源于stack exchange,提问作者Alfabrick12
相关产品推荐
相关产品推荐

