FastAPI Socketio WebSocket连接失败问题排查与解决
FastAPI + Socket.io WebSocket连接失败问题排查与解决
问题场景
使用FastAPI与Socket.io构建WebSocket服务时,出现前端连接失败的情况,相关代码如下:
ws.py
from loguru import logger import socketio from typing import List def handle_connect(sid, environ): logger.info(f"Socket connected with sid {sid}") class SocketManager: def __init__(self, origins: List[str]): self.server = socketio.AsyncServer( cors_allowed_origins=origins, async_mode="asgi", logger=True, engineio_logger=True, ) self.app = socketio.ASGIApp(self.server) @property def on(self): return self.server.on @property def send(self): return self.server.send def mount_to(self, path: str, app: socketio.ASGIApp): app.mount(path, self.app) socket_manager = SocketManager(origins=["*"]) socket_manager.on("connect", handler=handle_connect)
main.py
from ws import socket_manager app = FastAPI( title="MyBackend", docs_url="/docs", openapi_url="/openapi.json" ) app.include_router(router, prefix="/api/v1") socket_manager.mount_to("/ws", app)
错误信息
前端控制台报错
WebSocket connection to 'ws://localhost:80/ws/' failed
后端日志报错
RuntimeError: Expected ASGI message 'websocket.accept' or 'websocket.close', but got 'http.response.start'. DEBUG: > HTTP/1.1 101 Switching Protocols DEBUG: > Upgrade: websocket DEBUG: > Connection: Upgrade DEBUG: > Sec-WebSocket-Accept: TDJXRnQoVA7XR0L7D7yn+va91Q4= DEBUG: > Sec-WebSocket-Extensions: permessage-deflate DEBUG: > date: Sun, 26 Feb 2023 21:04:11 GMT DEBUG: > server: uvicorn INFO: connection open DEBUG: = connection is OPEN DEBUG: = connection is CLOSED DEBUG: ! failing connection with code 1006 DEBUG: x half-closing TCP connection INFO: connection closed
问题原因
- 参数类型错误:
SocketManager的mount_to方法参数标注为socketio.ASGIApp,但实际传入的是FastAPI实例,类型不匹配导致挂载逻辑异常。 - 连接路径错误:前端直接访问挂载路径
/ws/,但Socket.io要求客户端通过/socket.io子路径建立连接,直接访问根路径会被FastAPI当作普通HTTP请求处理,引发协议不匹配错误。
解决方法
1. 修复mount_to方法类型标注
修改ws.py中的mount_to方法,修正参数类型并导入FastAPI类型:
from fastapi import FastAPI # 新增导入 # ... 其他代码不变 def mount_to(self, path: str, app: FastAPI): # 将参数类型改为FastAPI app.mount(path, self.app)
2. 调整前端连接路径
Socket.io客户端需要通过/socket.io子路径连接,正确的WebSocket地址应为:
ws://localhost:80/ws/socket.io/?EIO=4&transport=websocket
若使用Socket.io官方客户端,初始化代码应改为:
const socket = io('http://localhost:80', { path: '/ws/socket.io' });
3. 验证修复后的完整代码
修正后的ws.py
from loguru import logger import socketio from typing import List from fastapi import FastAPI def handle_connect(sid, environ): logger.info(f"Socket connected with sid {sid}") class SocketManager: def __init__(self, origins: List[str]): self.server = socketio.AsyncServer( cors_allowed_origins=origins, async_mode="asgi", logger=True, engineio_logger=True, ) self.app = socketio.ASGIApp(self.server) @property def on(self): return self.server.on @property def send(self): return self.server.send def mount_to(self, path: str, app: FastAPI): app.mount(path, self.app) socket_manager = SocketManager(origins=["*"]) socket_manager.on("connect", handler=handle_connect)
修正后的main.py
from fastapi import FastAPI from ws import socket_manager app = FastAPI( title="MyBackend", docs_url="/docs", openapi_url="/openapi.json" ) app.include_router(router, prefix="/api/v1") socket_manager.mount_to("/ws", app)
额外说明
- 错误码1006属于Socket.io的异常关闭码,多数由协议不匹配、路径错误或CORS配置问题导致。
- Socket.io的ASGI应用挂载后,必须通过
/socket.io子路径建立连接,不能直接访问挂载的根路径。
内容的提问来源于stack exchange,提问作者haku
相关产品推荐
相关产品推荐

