Flask-SocketIO必须显式指定async_mode='eventlet'(开发推荐)或'gevent',禁用自动探测;WebSocket连接中request.args仅在connect时有效,session需手动存取;emit默认单播,广播须加broadcast=True;生产必须用gunicorn+eventlet启动并配置nginx透传Upgrade/Connection头。

Flask-SocketIO 初始化必须用 async_mode 参数明确指定异步模式
不指定 async_mode,Flask-SocketIO 会按顺序尝试 eventlet、gevent、threading,但多数开发环境(尤其 pip install 后直接跑)实际 fallback 到 threading 模式——它不支持真正的并发 WebSocket 连接,多用户时消息延迟高、甚至连接中断。生产环境几乎必然出问题。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 开发阶段直接固定为
async_mode='eventlet'(最稳定),并确保已安装:pip install eventlet - 初始化时写死:
socketio = SocketIO(app, async_mode='eventlet'),别依赖自动探测 - 如果用 gevent,必须提前
import gevent.monkey; gevent.monkey.patch_all(),且不能和 eventlet 共存 - Windows 下 eventlet 有 DNS 阻塞风险,可改用
async_mode='threading'仅限本地调试,切勿上生产
connect / disconnect 事件里不能直接访问 request.args 或 session
WebSocket 连接建立时的握手请求(GET /socket.io/...)携带的 query string 不会自动映射到后续的 connect 回调里的 request.args——这是常见误解。实际要用 request.args,得在客户端 connect 时显式传参,服务端从 request.args 读取;但更可靠的是走 request.sid + 自定义命名空间或房间管理。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 客户端连接时带参数:
io('http://localhost:5000', {query: {user_id: '123', token: 'abc'}}) - 服务端在
@socketio.on('connect')里用request.args.get('user_id')读取(仅限首次握手) -
session对象在 WebSocket 上默认不可用;如需用户状态,用socketio.save_session(sid, {'user_id': xxx})手动存,再用socketio.get_session(sid)取 - 别在
disconnect里做耗时操作(如 DB 写入),容易阻塞事件循环;改用异步任务或发到后台队列
emit() 默认只发给当前客户端,广播需显式加 broadcast=True
新手常以为 emit('message', data) 是“发给所有人”,结果发现只有自己收到。这是因为 Flask-SocketIO 的 emit() 默认作用域是当前 socket 连接(room=request.sid),不是全局广播。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 群聊场景必须加
broadcast=True:emit('chat', data, broadcast=True) - 想发给除自己外的所有人?用
include_self=False:emit('chat', data, broadcast=True, include_self=False) - 定向发给某房间:
emit('alert', data, room='lobby'),记得先join_room('lobby') - 跨命名空间发送要指定
namespace参数,否则发不到其他 namespace 的客户端
生产部署必须用 gunicorn + eventlet worker,不能用 flask run
flask run 启动的开发服务器完全不兼容 WebSocket 长连接,eventlet/gevent 的协程调度根本不会生效。上线后所有连接会卡在 pending 状态,或者秒断。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 启动命令必须是:
gunicorn --worker-class eventlet --workers 1 --bind "0.0.0.0:5000" --timeout 120 app:app - 不要设
--workers > 1:eventlet 单 worker 已支持数千并发,多 worker 反而因进程隔离导致房间/广播失效(除非用 Redis 消息队列) - nginx 配置里必须透传 Upgrade 和 Connection 头:
proxy_set_header Upgrade $http_upgrade;和proxy_set_header Connection "upgrade"; - 如果用 Docker,基础镜像选
python:3.11-slim而非alpine——eventlet 在 musl libc 下偶发崩溃
真正麻烦的从来不是写几行 emit 和 on,而是 async_mode 选错、部署漏掉 gunicorn、nginx 少配两个 header——这些地方一错,整个实时通信就静音了。











