flask原生不支持websocket,必须借助flask-socketio(配eventlet/gevent或asgi)、uvicorn+websockets等方案实现;硬套@app.route或werkzeug服务器会导致握手失败、400错误或静默断连。

Flask原生不支持WebSocket,别硬套flask自带路由
Flask 的 app.route 和 WSGI 服务器(如 Werkzeug、Gunicorn)根本处理不了 WebSocket 握手和持久连接。你写 @app.route('/ws') 然后返回 101 Switching Protocols,Werkzeug 会直接报错或静默断连——它压根不解析 Upgrade: websocket 头。这不是配置问题,是架构限制。
必须换用支持 ASGI 或原生 WebSocket 的服务层:
-
Flask-SocketIO:最常用,底层可选eventlet或gevent(需 monkey patch),也支持async_mode='asgi'配合uvicorn -
FastAPI + websockets:更现代,但这就不是 Flask 了 - 纯
websockets库 + 自建 HTTP 路由:绕过 Flask,自己处理静态文件和普通 API,WebSocket 单独跑一个websockets.serve实例
用Flask-SocketIO时,async_mode选哪个?
默认 async_mode='eventlet',但它要求所有 I/O 操作(比如数据库、HTTP 请求)都得兼容 eventlet 的协程调度,否则会阻塞整个连接池。常见坑:
- 用了
requests同步发请求?→ 必须换成eventlet.monkey_patch(),且得在 import 任何标准库前调用 - 用了
sqlite3?→ 默认线程锁机制和 eventlet 不兼容,容易死锁;建议换psycopg2+ PostgreSQL,或加check_same_thread=False(仅开发) - 想用
async/await写 handler?→ 得设async_mode='asgi',然后用uvicorn启动,此时socketio对象要从SocketIO(app, async_mode='asgi')初始化,且不能混用eventlet相关代码
简单项目推荐 async_mode='threading'(无并发压力时够用),高并发生产环境建议直接上 async_mode='asgi' + uvicorn --workers 2 app:app。
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
emit 和 send 的作用域差异很关键
这两个函数看着像,行为却完全不同:
-
send(data):只发给当前触发事件的客户端(即“单播”),适合响应用户操作,比如用户发消息后回个"已收到" -
emit('chat', data):默认也是单播;但加broadcast=True就变成广播(除发送者外所有人),加include_self=True才包含自己 - 想定向推给某房间?→ 先
join_room('room-123'),再emit('msg', data, to='room-123');注意to参数值是字符串,不是变量名 - 跨进程广播(比如多 worker)需要消息队列后端,如
redis:SocketIO(app, message_queue='redis://'),否则emit(..., broadcast=True)只在当前进程生效
前端连接不上?先检查Socket.IO客户端版本和路径
浏览器控制台报 WebSocket connection to 'ws://...' failed 或 400 Bad Request,90% 是因为前后端 Socket.IO 版本不匹配或路径没对齐:
- 服务端用的是
Flask-SocketIO==5.3.6(对应 Socket.IO 协议 v4),前端就得用socket.io-client@4.x,不能用@3.x或@latest(目前是 4.7+,兼容) - 默认挂载路径是
/socket.io/,前端 newio('http://localhost:5000')就行;但如果服务端配了path='/my-sock',前端必须显式写io('http://localhost:5000', { path: '/my-sock' }) - Nginx 反向代理 WebSocket 必须透传
Upgrade和Connection头,否则握手失败;配置里漏了proxy_set_header Upgrade $http_upgrade;这一行,前端就永远连不上
真实部署时,message_queue 选型、Nginx 配置、client 版本对齐,这三处出问题的概率远高于 Python 代码本身。










