You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>

关键修复点说明

  1. 独立摄像头实例:每个WebSocket连接创建新的cv2.VideoCapture(0),避免全局实例被释放后无法复用
  2. 扩展异常捕获:新增ConnectionClosedError捕获,处理客户端突然断开的情况
  3. 前端连接管理:封装WebSocket初始化逻辑,增加错误处理和可选重连,确保beforeunload时仅在连接打开状态下发送关闭请求

内容的提问来源于stack exchange,提问作者stud1234

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 01:10:21