
本文详解 fastapi 代理多路视频流时请求阻塞的根本原因——浏览器对单域名并发连接数的硬性限制(如 chrome/firefox 默认为 6),并提供可落地的优化方案,包括复用 http 客户端、隔离浏览器会话测试及服务端流式响应调优。
本文详解 fastapi 代理多路视频流时请求阻塞的根本原因——浏览器对单域名并发连接数的硬性限制(如 chrome/firefox 默认为 6),并提供可落地的优化方案,包括复用 http 客户端、隔离浏览器会话测试及服务端流式响应调优。
在构建实时视频监控、IoT 流媒体网关或在线教育平台时,常需通过 FastAPI 作为反向代理将远程 MJPEG/HTTP-Stream 视频源透传至前端。然而,开发者常遇到一个典型现象:当同时打开 5 个视频流页面时一切正常;一旦开启第 6 路,后续所有 API 请求(包括健康检查、登录接口等)全部卡住,直到关闭任一已打开的流页面才恢复响应。这并非 FastAPI 或 Uvicorn 的性能瓶颈,而是一个被广泛忽视但至关重要的客户端限制问题。
? 根本原因:浏览器并发连接数上限
现代主流浏览器(Chrome、Firefox、Edge)对同一主机名(如 http://localhost:8000)强制实施 HTTP/1.1 并发连接数限制,默认值为 6。该限制由浏览器内核硬编码,无法通过前端代码绕过。当你的前端页面通过 <img src="/get_stream?url=..."> 或 fetch() 同时发起 6 个 /get_stream 请求时,第 7 个请求将被浏览器直接挂起(stalled),进入队列等待空闲连接,而非发送至服务器——这意味着 FastAPI 根本收不到该请求,自然不会触发任何日志或超时逻辑。
✅ 验证方法:打开 Chrome DevTools → Network → 查看请求状态栏,若显示 “stalled”,即为浏览器连接池耗尽,非后端故障。
? 正确解决方案
1. 复用全局 HTTP 客户端(避免资源泄漏)
原示例中每次请求都新建 httpx.AsyncClient(),不仅开销大,还易引发连接未及时释放问题。应改用应用生命周期管理的单例客户端:
import uvicorn
import httpx
from fastapi import FastAPI, Depends
from fastapi.responses import StreamingResponse
app = FastAPI()
# 全局复用的异步 HTTP 客户端
http_client = httpx.AsyncClient(
timeout=httpx.Timeout(30.0, connect=10.0),
limits=httpx.Limits(max_connections=100, max_keepalive_connections=20)
)
@app.on_event("shutdown")
async def shutdown_event():
await http_client.aclose()
async def proxy_mjpeg_stream(url: str):
try:
async with http_client.stream("GET", url) as stream:
# 设置合适的 chunk size,避免小包频繁 flush
async for chunk in stream.aiter_bytes(chunk_size=8192):
yield chunk
except httpx.TimeoutException as e:
raise HTTPException(status_code=504, detail=f"Upstream timeout: {e}")
except httpx.HTTPStatusError as e:
raise HTTPException(status_code=e.response.status_code, detail="Upstream error")
@app.get("/get_stream")
async def get_stream(url: str):
if not url:
raise HTTPException(status_code=400, detail="URL parameter is required")
headers = {
"Content-Type": "multipart/x-mixed-replace; boundary=frame",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
}
return StreamingResponse(proxy_mjpeg_stream(url), headers=headers)
2. 前端规避策略:子域名分流或 Service Worker 缓存
-
子域名分流:将不同视频流路由至
stream1.yourdomain.com、stream2.yourdomain.com等,每个子域享有独立的 6 连接配额; -
Service Worker 拦截:用 SW 统一管理流请求,实现连接复用与失败重试,避免直接暴露
/get_stream给浏览器原生请求机制。
3. 测试务必脱离浏览器主会话
使用 httpx 或 curl 进行压测时,可突破浏览器限制:
# 并发 20 路请求(验证后端真实承载力)
for i in {1..20}; do
curl -s "http://localhost:8000/get_stream?url=https://example.com/stream$i.mjpg" > /dev/null &
done
wait
若此时无阻塞,则 100%确认问题出在浏览器层。
⚠️ 注意事项与最佳实践
-
禁用浏览器预加载:在
<img>标签中添加loading="lazy"和decoding="async",防止滚动时批量触发连接; -
设置合理的超时与重连:前端 JS 应监听
onerror并自动重连,后端返回504 Gateway Timeout时前端主动重建流; - 生产环境启用 HTTP/2:Uvicorn + Nginx 反向代理配置 HTTP/2,可显著提升多路流复用效率(单 TCP 连接承载多路流);
-
监控连接状态:通过
uvicorn的--log-level debug查看connection open/close日志,辅助定位连接泄漏。
综上,该问题本质是“客户端能力边界”而非“服务端缺陷”。理解并尊重浏览器网络栈的设计约束,结合服务端资源复用与前端架构优化,才能构建真正高并发、高可用的视频流代理系统。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











