FastAPI(Uvicorn)中WebSocket在浏览器/移动端60-70秒后断开,Postman正常
解决FastAPI+Uvicorn WebSocket在浏览器/移动端60-70秒断开的问题
问题背景
使用FastAPI搭配Uvicorn搭建WebSocket服务,Postman测试连接全程稳定,但浏览器、Flutter移动端连接后约60-70秒会自动断开。已尝试配置Uvicorn的WebSocket保活参数但未解决,未使用反向代理服务器,且未配置SSL/TLS却使用wss://协议发起连接。
核心疑问解答
1. 为何浏览器/移动端断开但Postman正常?
- Postman对WebSocket的连接超时策略更宽松,且默认自带的保活机制更主动,不会轻易被客户端侧网络(如家用路由器、移动运营商网关)的空闲连接回收策略触发断开。
- 浏览器、移动端的WebSocket受引擎/系统网络栈限制,同时客户端所在网络通常会对空闲TCP连接设置60-90秒的超时回收规则,如果连接期间没有持续的数据包交互,就会被强制断开。
2. 未配置SSL/TLS是否会导致断开?
- 会。
wss://是基于TLS加密的WebSocket协议,服务器未配置SSL/TLS时,浏览器发起wss://请求会出现协议不匹配,连接建立后可能因加密层异常被主动断开,或后续交互中因数据包格式错误触发终止。你日志中使用wss://但未配置SSL/TLS,这是核心问题之一。
3. 如何实现跨客户端长连接?
给出可落地的配置与代码调整方案:
1. 修正协议与SSL配置
- 若服务器未配置SSL/TLS,客户端必须使用
ws://而非wss://发起连接;若需wss://,给Uvicorn配置SSL证书:
命令行启动方式:
代码启动方式:uvicorn main:app --host 0.0.0.0 --port 7000 --ssl-keyfile ./private.key --ssl-certfile ./cert.pemuvicorn.run( "main:app", host='0.0.0.0', port=7000, ssl_keyfile="./private.key", ssl_certfile="./cert.pem" )
2. 统一Uvicorn保活参数配置
- 之前代码启动(
uvicorn.run())未加入保活参数,导致配置无效。需在代码启动时添加对应参数,且注意reload=True与workers>1不兼容,生产环境需移除reload:uvicorn.run( "main:app", host='0.0.0.0', port=7000, workers=4, # 生产环境使用,开发时可去掉 ws_ping_interval=20, # 间隔小于网络超时(建议20秒) ws_ping_timeout=40 )
3. 实现双向心跳机制
- 仅靠服务器端ping可能不够,需在业务逻辑中添加主动心跳:
客户端(浏览器/Flutter)需监听心跳包并回复,确保连接有持续数据交互,避免被网络判定为空闲。from fastapi import WebSocket import asyncio async def websocket_chat_endpoint(websocket: WebSocket): await websocket.accept() # 服务器主动发送心跳 async def send_heartbeat(): while True: await asyncio.sleep(20) await websocket.send_text("heartbeat") # 启动心跳任务 heartbeat_task = asyncio.create_task(send_heartbeat()) try: while True: data = await websocket.receive_text() # 处理业务逻辑 await websocket.send_text(f"Received: {data}") except WebSocketDisconnect: heartbeat_task.cancel() print("客户端连接断开")
4. 排查客户端侧网络
- 检查客户端所在路由器的TCP空闲超时设置,必要时调整;移动端测试尽量避免弱网环境,弱网下更容易触发连接中断。
内容的提问来源于stack exchange,提问作者Shivaditya kr
相关产品推荐
相关产品推荐

