You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.pem
    
    代码启动方式:
    uvicorn.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可能不够,需在业务逻辑中添加主动心跳:
    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("客户端连接断开")
    
    客户端(浏览器/Flutter)需监听心跳包并回复,确保连接有持续数据交互,避免被网络判定为空闲。
4. 排查客户端侧网络
  • 检查客户端所在路由器的TCP空闲超时设置,必要时调整;移动端测试尽量避免弱网环境,弱网下更容易触发连接中断。

内容的提问来源于stack exchange,提问作者Shivaditya kr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 06:05:56