ESP32 监控中台:Vue 3 的实时视频界面
从多路视频流、端口管理到权限与部署,记录实验室监控中心的前端结构与工程取舍。
本文目录
monitor 是一个面向 ESP32-S3 摄像头集群的实验室监控前端。它把多路视频、设备端口和系统配置放在同一个 Vue 3 应用里,后端通过 HTTP API 管理节点,视频流则由每台设备独立推送。
技术栈与页面
项目使用 Vue 3(Composition API + <script setup>)、TypeScript、Vite、Element Plus、Pinia、Vue Router 和 Axios,视频解码使用 jmuxer。
| 页面 | 职责 |
|---|---|
| 实时预览 | 多路 MJPEG / WebSocket 视频流,支持展开与关闭 |
| 历史录像 | 录像文件查询与回放 |
| 通讯终端 | 节点端口状态、启停管理 |
| 系统配置 | 设备调度与系统参数(管理员) |
| 登录/角色 | 访客只读、管理员可操作 |
侧边栏在桌面端常驻,移动端切换为抽屉导航;主题偏好保存在本地。
视频流:WebSocket 与 jmuxer
H.264 流通过 WebSocket 以二进制帧到达,前端把每一帧交给 jmuxer 解码到 <video>。关键不是“能播”,而是断流、重连和组件卸载时不要留下定时器。
ws = new WebSocket(props.streamUrl)
ws.binaryType = 'arraybuffer'
ws.onmessage = (event) => {
jmuxer.feed({ video: new Uint8Array(event.data) })
}
ws.onclose = () => {
if (destroyed) return
reconnectTimer = window.setTimeout(connect, 2000)
}
组件卸载时会清空首次连接与重连定时器、摘掉 onclose 后主动关闭 WebSocket,并销毁 jmuxer;否则离开页面后仍可能继续建连。MJPEG 模式则直接使用 HTTP 流地址,不经过 jmuxer。
配置集中在一个文件
最容易出问题的不是请求本身,而是地址散落在各处。项目把 API 与流地址收敛到 src/config.ts:
export const API_BASE =
import.meta.env.VITE_API_BASE ?? 'http://<YOUR_SERVER_IP>:3000/api'
export const STREAM_HOST =
import.meta.env.VITE_STREAM_HOST ?? '<YOUR_SERVER_IP>'
节点只保存端口,URL 由 streamHttpUrl(port) / streamWsUrl(port) 拼接。换服务器只需要改 .env,不用搜索替换业务代码。
节点与端口管理
节点模型很克制:
interface DeviceNode {
id: string
udp: number
http: number
}
Pinia 里的 usedPorts 会把所有节点的 UDP/HTTP 端口收进一个集合,启动新节点前检查冲突;界面上 UDP 范围是 9001–9050,HTTP 范围是 9051–9100,已占用端口会标红。启停、重置等操作只对管理员开放,普通访客只能看流。
权限:客户端门禁不是安全边界
项目用 VITE_ADMIN_PASSWORD 做前端管理员门禁,登录状态存在 localStorage。这适合实验室内网演示,但必须明确:构建进前端的密码不是授权机制。任何能拿到前端资源的人都能绕过它,真正的启停与配置接口必须在服务端校验身份。
如果要把这套系统放到不可信网络,至少需要:
- 服务端会话或 Token 校验;
- 对启停、重置、配置等写接口做权限控制与审计;
- 不再把管理员密码放进
VITE_*变量。
部署
仓库提供了一个 Windows 一键脚本:构建后通过 SSH 清理旧目录,SCP 上传 dist/,再更新 Nginx 权限。脚本里的服务器地址是占位值,部署前必须替换;生产环境更建议把部署步骤放进 CI,而不是把凭据留在批处理文件旁边。
复盘
- 视频类页面的重点在生命周期管理:断流重连、卸载清理、重复建连。
- 配置集中化能显著降低部署与排错成本。
- 角色分离要前后端一起做;前端门禁只负责界面状态。
- 监控系统没有“差不多能看”这一说,端口冲突和权限边界都要在代码里写清楚。
讨论
评论由 GitHub Discussions 提供,点击后加载。未加载前不会产生第三方请求。