当前位置: 首页 > news >正文

FastAPI 实战:WebSocket 从入门到上线,使用避坑指南

💬 你是不是觉得 WebSocket 挺简单的?不就建立个连接,然后 send 和 onmessage 吗?
我当初也这么想,直到我做了一个在线协作小工具,上线第一天晚上,服务器直接崩了,用户疯狂吐槽:“怎么画着画着就断了?” 那一晚,我盯着监控面板,才真正明白——WebSocket 的坑,不在握手,而在长连接的战场上。

📌 本文摘要:从 FastAPI 实战出发,分享在生产环境中用 WebSocket 踩过的坑、填坑的方案,以及那些容易忽略的注意事项。读完你不仅能跑通 Demo,还能让连接更稳定,心里更有底。

🚀 FastAPI 实战:WebSocket 使用避坑指南,让你的长连接稳如老狗

🎯 这篇你会得到什么:

🔹 第一部分:WebSocket 的本质(用一个餐厅的故事讲透)

🔹 第二部分:FastAPI 集成 WebSocket 的最小实战(带代码)

🔹 第三部分:5 个最常见翻车点及解决方案(心跳、认证、并发、部署、异常)

🔹 第四部分:老程序员的碎碎念(经验总结 + 互动)

🍳 1. 先从 WebSocket 是什么聊起(一个餐厅的比喻)

传统的 HTTP 请求,就像你去餐厅点菜:你喊一声“服务员,来份宫保鸡丁”,然后服务员跑去后厨,把菜端给你,一次交易结束。你要再点个米饭,又得喊一次。

而 WebSocket 呢?它就像你直接在餐厅包了个雅间,服务员就站在你桌旁,随时听你吩咐:“加点水”、“拿头蒜”、“结账” —— 服务员一直在线,随时响应,省去了反复呼叫的过程。

FastAPI 对 WebSocket 的支持非常 Pythonic,用起来很顺手,但正因为顺手,容易忽略背后那些“服务员也得休息”、“包间太多会拥挤”的现实问题。

⚡ 2. 最小实战:一个简单的聊天 echo 服务

先来个最基础的,看看 FastAPI 里 WebSocket 长啥样。下面的代码实现了一个 echo 功能:客户端发什么,我就原样返回什么。

from fastapi import FastAPI, WebSocket, WebSocketDisconnectapp = FastAPI()@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):await websocket.accept()try:while True:# 接收客户端消息data = await websocket.receive_text()# 原样返回await websocket.send_text(f"服务端收到: {data}")except WebSocketDisconnect:print("客户端断开连接")except Exception as e:print(f"发生异常: {e}")# 记得主动关闭连接await websocket.close()

看着是不是很简单?✨ 但这里已经藏着一个坑:如果客户端异常断开(比如网络闪断),receive_text() 会抛出 WebSocketDisconnect,你得捕获它,否则程序会崩溃。我曾经没写这个 try,结果 uvicorn 进程直接挂掉,教训惨痛。

💣 3. 五个让你凌晨三点爬起来填的坑(附解决方案)

👉 3.1 连接自动断开?因为没有心跳

很多云服务商(比如阿里云、AWS)的负载均衡器,如果一段时间内没有数据传输,会认为连接空闲而把它掐掉。这个时间通常是 60 秒左右。

解决方案: 服务端和客户端都要有心跳机制。最简单的做法是客户端每隔 30 秒发一个 ping 帧(或者自定义心跳消息),服务端收到后回复 pong。

当初我偷懒没做心跳,用户画图时停顿超过 1 分钟就掉线,被产品经理追着打。😭 后来加了个定时器,世界安静了。

# 服务端处理心跳的伪代码
async def websocket_endpoint(websocket: WebSocket):await websocket.accept()while True:try:# 设置接收超时,如果一段时间没收到任何消息,主动发心跳探测data = await asyncio.wait_for(websocket.receive_text(), timeout=30)# 处理正常消息except asyncio.TimeoutError:# 30 秒没收到消息,主动发送 ping 探测await websocket.send_text("__ping__")  # 自定义心跳# 如果客户端没响应,会在下一次循环触发 WebSocketDisconnect

👉 3.2 WebSocket 握手时如何携带 Token?

WebSocket 的握手是 HTTP 请求,所以可以在 URL 参数或者 Header 里带 token。但千万不要在路径里明文传 token,会记在日志里!

推荐的做法:用 Sec-WebSocket-Protocol 或者 Header 里的 Authorization。FastAPI 的依赖注入也支持 WebSocket,你可以写一个依赖来校验。

from fastapi import WebSocket, WebSocketException, statusasync def get_cookie_or_token(websocket: WebSocket):# 从 query 参数或 header 取 token(示例从 query 取)token = websocket.query_params.get("token")if token != "secret":await websocket.close(code=status.WS_1008_POLICY_VIOLATION)raise WebSocketException("认证失败")return token@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket, token: str = Depends(get_cookie_or_token)):await websocket.accept()# ...

👉 3.3 连接数一高,服务就卡死?

每个 WebSocket 连接都会占用一个系统文件描述符和内存。默认的 uvicorn 单进程能支撑的连接数有限(取决于你机器配置)。如果直接裸跑,内存可能会被慢慢吃光。

解决方案:

🔹 用 gunicorn + uvicorn workers 启动多进程,注意设置适当的 worker 数量,一般 = CPU 核心数 * 2。

🔹 如果广播消息频繁,不要用简单的全局循环给所有连接发,可以用 asyncio.gather 并发发送,但注意控制并发数,防止突发流量把 CPU 打满。

🔹 考虑使用 Redis 等中间件做消息分发,特别是多进程模式下,一个进程不知道另一个进程管理的连接,需要借助外部广播。

⚠️ 线上教训:我曾用单进程跑了 5000 个连接,结果内存占用 2GB,频繁 GC,最后用 --workers 4 解决了,但广播又成了新问题,后来引入了 Redis pub/sub。

👉 3.4 服务重启时,用户瞬间掉线怎么办?

当你部署新版本,需要重启服务,所有 WebSocket 连接会被粗暴关闭。用户会看到“连接已断开”。这很不优雅。

解决方案: 利用 uvicorn 的 lifespan 事件,在关闭前主动通知客户端(比如发一条“服务即将维护”的消息),并等待几秒再关闭。也可以配合负载均衡的 draining 机制。

# 在 shutdown 事件里做清理
@app.on_event("shutdown")
async def shutdown_cleanup():# 遍历所有活跃连接,发下线通知for connection in active_connections:try:await connection.send_text("server going down, reconnect later")except:pass# 等 1 秒让消息发出去await asyncio.sleep(1)

👉 3.5 文本还是二进制?JSON 还是自定义?

WebSocket 支持文本和二进制帧。如果你们前后端约定用 JSON,记得处理解析异常。我曾经因为前端发了个非法的 JSON,服务端没捕获 json.JSONDecodeError,直接导致连接崩溃。

稳健的做法: 统一用 receive_json() 并捕获异常,给客户端返回错误码,而不是断开连接。

🧠 4. 程序媛的碎碎念:从能用→好用→稳如泰山

WebSocket 的上手门槛确实低,但想在生产环境跑得稳,你需要考虑这些:

✅ 监控:每一条连接的存活时间、收发消息数量,最好都能通过 metrics 暴露出来(比如用 Prometheus)。

✅ 限流:单个用户发消息太快怎么办?可以用漏桶或令牌桶限制频率,防止被恶意攻击。

✅ 断线重连:客户端一定要有自动重连机制,指数退避策略,避免同时重连造成服务器压力。

✅ 测试:用 websockets 库写脚本模拟数千个连接,压测一下你的服务,看资源占用和响应延迟。

我还记得有一次,我忘记设置 max_size 限制,客户端传了个超大的消息,直接把内存撑爆了。后来在 accept 之前加上 websocket.max_size = 1_048_576 (1MB),世界又清净了。


老朋友,今天的分享就到这里。如果你也在 FastAPI 里踩过 WebSocket 的坑,或者有什么独家秘笈,欢迎留言区切磋。

⭐️ 觉得有用的话,点个赞 再走呗,这样我下回才有动力写出更多FastAPI 避坑指南。
当然,关注我也可以,毕竟你不知道我下次又会因为什么骚操作,给你带来新的实战经验~ 😉

http://www.jsqmd.com/news/384373/

相关文章:

  • API接口管理平台:企业数字化转型的神经网络
  • 少走弯路:千笔·专业降AI率智能体,碾压级的降AI率软件
  • 2026年热门的重型带座外球面轴承/低噪音带座外球面轴承新厂实力推荐(更新) - 品牌宣传支持者
  • 2026年靠谱的烤漆玻璃加工/夹丝玻璃加工高口碑厂家推荐(评价高) - 品牌宣传支持者
  • 2026年靠谱的翡翠水头/翡翠戒指厂家选购参考建议 - 品牌宣传支持者
  • 2026年质量好的南通数控龙门磨床/南通龙门导轨磨床厂家选择参考建议 - 品牌宣传支持者
  • 2026年质量好的microLED显示屏/晶膜LED显示屏用户口碑认可厂家 - 品牌宣传支持者
  • 2026年评价高的乌鲁木齐预约审车/乌鲁木齐本地审车实力工厂参考怎么选 - 品牌宣传支持者
  • 2026年口碑好的非标定制外球面轴承/防尘密封外球面轴承优质厂家推荐汇总 - 品牌宣传支持者
  • 用实力说话千笔,断层领先的降AIGC网站
  • 上海公司注销哪家好? - 品牌企业推荐师(官方)
  • 万字长文深度解析 RAG
  • 超图技术提升产品检索性能
  • 2026年比较好的洛阳无人机表演培训/洛阳无人机执照培训哪家便宜源头直供参考(真实参考) - 品牌宣传支持者
  • 2026年热门的低温除湿机/除湿机厂家推荐与选择指南 - 品牌宣传支持者
  • 支付宝消费券回收流程详解及专业平台优势解析 - 京顺回收
  • 真心不骗你 10个AI论文工具测评:本科生毕业论文写作必备指南
  • 2026年质量好的钢化玻璃/艺术玻璃厂家信誉综合参考 - 品牌宣传支持者
  • 深度测评 8个AI论文网站:本科生毕业论文写作全攻略
  • 2026年2月云南新能源车出租公司测评,节能省钱租赁平台优选 - 品牌鉴赏师
  • 读《控制论与科学方法论》
  • 2026年口碑好的高杆灯球场路灯/扬州景观路灯厂家口碑推荐汇总 - 品牌宣传支持者
  • [英语]-介词和动词
  • 2026年靠谱的单悬臂标志杆/扬州道路交通标志杆厂家最新推荐 - 品牌宣传支持者
  • 2026年评价高的兰州石笼网/兰州石笼网箱高评价厂家推荐 - 品牌宣传支持者
  • 扫描仪校准周期多久?优秀售后表现的三维扫描仪品牌推荐 - 匠言榜单
  • 2月热门!2026年检测试剂盒品牌哪家好引关注,细胞因子检测试剂盒/鱼试剂盒/大鼠试剂盒,检测试剂盒厂家有哪些 - 品牌推荐师
  • 2026年可靠的护栏网/兰州小区围墙护栏网厂家质量参考评选 - 品牌宣传支持者
  • 2026年比较好的常熟印花水刺无纺布/常熟染色水刺无纺布厂家推荐与采购指南 - 品牌宣传支持者
  • 2026年口碑好的大连艺术留学公司/大连艺术留学作品集辅导最新推荐公司 - 品牌宣传支持者