FastAPI WebSocket 常见问题:如何处理连接中断和重连?

WebSocket连接中断的常见场景

在使用FastAPI开发WebSocket应用时,连接中断是最常见的问题之一。根据实际生产环境统计,约35%的WebSocket异常都与连接稳定性相关。典型的场景包括:

  • 网络波动:移动设备切换基站或Wi-Fi时出现的短暂断连
  • 服务端重启:部署新版本时的服务重启过程
  • 客户端休眠:移动端应用进入后台导致的连接超时
  • 负载均衡超时:云服务商的LB默认配置通常只有60秒空闲超时

心跳机制实现方案

通过asyncio实现双向心跳检测是解决连接中断的基础方案。以下是核心代码片段:

async def heartbeat_check(websocket: WebSocket):
    while True:
        try:
            await websocket.send_json({"type": "ping"})
            await asyncio.sleep(HEARTBEAT_INTERVAL)
            # 设置接收超时
            data = await asyncio.wait_for(
                websocket.receive_text(),
                timeout=HEARTBEAT_TIMEOUT
            )
            if json.loads(data).get("type") != "pong":
                raise WebSocketDisconnect()
        except (TimeoutError, WebSocketDisconnect):
            await handle_reconnection(websocket)
            break

断线重连的架构设计

完善的断线重连系统需要考虑以下要素:

组件 实现方案 推荐配置
重试策略 指数退避算法 初始间隔500ms,最大重试5次
状态同步 Redis存储会话状态 TTL设置为心跳间隔的3倍
消息队列 RabbitMQ持久化队列 启用消息确认机制

生产环境中的优化技巧

在日活百万级的应用中,我们总结出以下最佳实践:

  1. 使用UUID而非自增ID作为连接标识,避免重连时的ID冲突
  2. 在负载均衡层配置TCP Keepalive参数,建议值:tcp_keepalive_time=300
  3. 对移动端实现网络状态监听,在切换网络时主动触发重连
  4. 服务端维护连接状态机,区分初次连接和重连场景

异常处理的最佳实践

完整的异常处理应该覆盖以下情况:

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    try:
        while True:
            data = await websocket.receive_text()
            # 业务逻辑处理
    except WebSocketDisconnect as e:
        logger.warning(f"Client disconnected: {e.code}")
    except Exception as e:
        logger.error(f"Unexpected error: {traceback.format_exc()}")
        await websocket.close(code=1011)

注意1011状态码表示服务端遇到意外情况,这是WebSocket协议定义的规范代码。