FastAPI WebSocket摄像头流异常:页面重载/关闭报错且无法重连
问题解决:FastAPI WebSocket摄像头流重载失败及连接关闭报错
核心问题分析
你的代码存在三个关键问题:
- 全局
camera实例被释放后未重新初始化:第一次连接关闭时finally块执行camera.release(),后续连接复用已释放的实例,导致无法读取帧 - 异常捕获范围不足:
ConnectionClosedError未被捕获,导致服务端抛出错误 - 客户端关闭连接时,服务端的
WebSocketDisconnect未触发,因为客户端beforeunload事件中ws.close()可能未完成握手页面就已卸载
修复后端代码
from fastapi import FastAPI, WebSocket, Request, WebSocketDisconnect from fastapi.templating import Jinja2Templates import cv2 from websockets.exceptions import ConnectionClosedError app = FastAPI() templates = Jinja2Templates(directory="templates") async def get_video_frame(camera): while True: success, frame = camera.read() if not success: break _, buffer = cv2.imencode('.jpg', frame) yield buffer.tobytes() @app.get("/", response_class=HTMLResponse) async def index(request: Request): return templates.TemplateResponse("index.html", {"request": request}) @app.websocket("/ws") async def get_stream(websocket: WebSocket): await websocket.accept() camera = None try: # 每个连接创建独立的摄像头实例 camera = cv2.VideoCapture(0) async for frame in get_video_frame(camera): await websocket.send_bytes(frame) except WebSocketDisconnect: print("Client disconnected via WebSocket disconnect") except ConnectionClosedError: print("Client connection closed abruptly") finally: if camera is not None: camera.release() print("Camera resource released")
修复前端代码
客户端增加连接管理逻辑,确保连接正常关闭并优化重连体验:
<!DOCTYPE html> <html> <head> <title>Live Streaming</title> </head> <body> <img id="frame" src=""> <script> let ws; let image = document.getElementById("frame"); function initWebSocket() { ws = new WebSocket(`ws://${window.location.host}/ws`); image.onload = function(){ URL.revokeObjectURL(this.src); }; ws.onmessage = function(event) { image.src = URL.createObjectURL(event.data); }; ws.onclose = function(event) { console.log("WebSocket closed:", event); // 可选:断开后自动尝试重连 setTimeout(initWebSocket, 2000); }; ws.onerror = function(error) { console.error("WebSocket error:", error); }; } // 初始化连接 initWebSocket(); window.addEventListener('beforeunload', function() { if (ws && ws.readyState === WebSocket.OPEN) { ws.close(1000, "Page unloaded"); } }); </script> </body> </html>
关键修复点说明
- 独立摄像头实例:每个WebSocket连接创建新的
cv2.VideoCapture(0),避免全局实例被释放后无法复用 - 扩展异常捕获:新增
ConnectionClosedError捕获,处理客户端突然断开的情况 - 前端连接管理:封装WebSocket初始化逻辑,增加错误处理和可选重连,确保
beforeunload时仅在连接打开状态下发送关闭请求
内容的提问来源于stack exchange,提问作者stud1234
相关产品推荐
相关产品推荐

