fastapi 本身不提供 @app.websocket() 装饰器,因其 websocket 支持完全委托给 starlette,需用 app.add_websocket_route() 显式注册;漏调 await websocket.accept() 或协议/路径配置错误是连接失败主因。

FastAPI 本身不提供 app.websocket() 装饰器,必须通过 Starlette 的 WebSocket 类 + app.add_websocket_route() 手动注册,否则会报 AttributeError: 'FastAPI' object has no attribute 'websocket'。
为什么不能用 @app.websocket?
FastAPI 没有实现 websocket 方法——这个常见误解源于对 Flask 或其他框架习惯的迁移。它的 WebSocket 支持完全委托给底层 Starlette,因此没有装饰器语法糖。直接写 @app.websocket("/ws") 会立刻抛出 AttributeError。
- FastAPI 的路由系统只默认暴露
get、post等 HTTP 方法,websocket不在其中 - 所有 WebSocket 处理函数必须显式接受
WebSocket类型参数(来自starlette.websockets) - 必须调用
app.add_websocket_route()注册,且路径不能与其他 HTTP 路由冲突
websocket.accept() 必须在循环外调用一次
客户端发起连接后,服务端必须主动调用 await websocket.accept(),否则连接会被立即关闭,浏览器控制台显示 WebSocket connection to 'ws://localhost:8000/ws' failed。
- 漏掉这行是 WebSocket 连接失败最常见原因
- 不能放在
while True循环里重复调用(会报RuntimeError: Already accepted) - 如果需要鉴权,应在
accept()前检查 token 或 session,失败则直接await websocket.close(code=4001)
后台任务必须用 asyncio.create_task(),不是 BackgroundTasks
在 WebSocket 连接生命周期中调用 background_tasks.add_task() 是无效的:它依赖 HTTP 请求上下文,而 WebSocket 没有“请求结束”这一节点,任务永远不会触发。
- 正确做法是用
asyncio.create_task()启动协程,并保存引用(例如存入set防止被 GC) - 务必手动捕获异常,否则崩溃无声:
try/except包裹任务体 +logger.exception() - 连接断开时,应主动
task.cancel()并await task清理资源(如 Redis Pub/Sub 订阅)
前端连接 URL 必须用 ws:// 或 wss://,不能用 http://
浏览器中 new WebSocket("http://localhost:8000/ws") 会报错 Failed to construct 'WebSocket': The URL's scheme must be either 'ws' or 'wss'。协议错误是新手最常卡住的点。
- 开发环境用
ws://localhost:8000/ws - 部署到 Nginx 反代后,确保配置了
Upgrade和Connectionheader,否则握手失败 - 若后端跑在 HTTPS 域名下,前端必须用
wss://,否则浏览器直接拦截
WebSocket 连接一旦建立,就脱离 FastAPI 的中间件链和依赖注入作用域——比如你在 HTTP 路由里能用的 Depends(get_current_user),在 WebSocket 函数里无法直接复用,得自己解析 token 并验证。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











