
本文详解 fastapi 代理多路视频流时请求阻塞的根本原因——浏览器对单域名并发连接数的硬性限制(如 chrome/firefox 默认为 6),并提供服务端复用 http 客户端、客户端隔离会话及跨域分流等实战解决方案。
本文详解 fastapi 代理多路视频流时请求阻塞的根本原因——浏览器对单域名并发连接数的硬性限制(如 chrome/firefox 默认为 6),并提供服务端复用 http 客户端、客户端隔离会话及跨域分流等实战解决方案。
在使用 FastAPI 构建视频流代理服务时,开发者常遇到一个看似服务端瓶颈、实则源于客户端限制的典型问题:当同时打开 6 个及以上 /get_stream 流式响应标签页时,后续请求立即停滞,直到关闭任一已建立的流连接。这并非 FastAPI 或 Uvicorn 的性能缺陷,而是现代浏览器对同一主机名(hostname)强制实施的并行 TCP 连接数上限所致。
? 根本原因:浏览器连接池限制
主流浏览器对单域名并发连接数有严格限制:
- Chrome、Firefox、Edge:默认 6 个 HTTP/1.1 连接
- Safari:通常为 6–8 个
该限制由浏览器内核硬编码,目的是防止资源耗尽和 DoS 风险。由于StreamingResponse建立的是长连接(HTTP Keep-Alive),每个视频流独占一个连接槽位。第 7 个请求将被浏览器静默排队,直至前序某连接释放——这正是“请求 stall”的真实来源。
✅ 验证方法:使用
httpx.AsyncClient编写脚本并发请求(不经过浏览器),可轻松突破 50+ 并发流而无阻塞,证明服务端完全健康。
?️ 解决方案一:服务端复用 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, read=60.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:
async for chunk in stream.aiter_bytes():
if chunk:
yield chunk
except httpx.ReadTimeout as e:
print(f"Read timeout for {url}: {e}")
except Exception as e:
print(f"Stream error for {url}: {e}")
@app.get("/get_stream")
async def get_stream(url: str):
if not url:
return {"error": "URL 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)
✅ 关键改进:
-
httpx.AsyncClient实例全局单例,复用底层连接池; -
limits显式配置最大连接数(max_connections=100),避免客户端侧耗尽; -
on_event("shutdown")确保优雅关闭,防止连接泄漏。
? 解决方案二:客户端分流策略(推荐)
若需支持大量并发流,必须绕过单域名限制:
| 方案 | 实现方式 | 优点 | 注意事项 |
|---|---|---|---|
| 子域名分流 | 配置 stream1.example.com, stream2.example.com 等多个子域,DNS 轮询或反向代理分发 |
浏览器视为不同主机,各自拥有 6 连接配额 | 需 DNS/CDN 支持,HTTPS 证书需通配符 |
| 端口分流 | 启动多个 Uvicorn 实例(如 :8001, :8002),前端按需切换端口 |
无需额外域名,开发调试便捷 | 生产环境需反向代理统一入口 |
| Service Worker 缓存代理 | 前端用 SW 拦截 /get_stream 请求,复用已有连接或降级为轮询 |
完全客户端控制,规避浏览器限制 | 需额外前端工程,兼容性需验证 |
? 小技巧:Chrome 中可通过
chrome://net-internals/#sockets实时查看当前所有连接状态,快速定位阻塞源头。
⚠️ 注意事项与最佳实践
-
禁用浏览器预加载/预连接:在 HTML 中添加
<meta http-equiv="Cache-Control" content="no-store">,防止浏览器主动预建连接; -
设置合理的超时:流式响应务必配置
read_timeout(建议 ≥60s),避免因网络抖动中断; -
监控连接数:在生产环境集成 Prometheus +
uvicorn[standard],暴露uvicorn.connections.active指标; -
避免
StreamingResponse与BackgroundTasks混用:流式响应生命周期由客户端控制,后台任务无法安全接管流数据。
通过服务端连接池优化 + 客户端域名/端口分流,FastAPI 可稳定支撑数百路并发视频流代理。记住:真正的瓶颈往往不在代码里,而在你打开的浏览器标签页中。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











