尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
基于Vue的EasyMedia-ui:RTSP转FLV流媒体播放前端实践与部署指南
简介EasyMedia-ui.zip 是一套面向流媒体直播与点播场景的 Vue.js 前端页面方案内置 RTSP、FLV 播放支持及单屏/四分屏/九分屏/十六分屏布局适合开发者直接集成、二次改造也可作为前端工程师学习流媒体交互与组件化开发的参考。包内共 22 个文件仅 101KB以 7 个 js 和 7 个 vue 源码为核心辅以 json 配置、html 入口、ico/png 图标以及 eslint、babel 等工程化配置目录结构清晰从 public 静态资源到 src 源码目录一应俱全路由、状态管理与 HTTP 接口封装均独立成模块便于按需阅读。目前已有 16570 人学习下载涵盖完整前端工程骨架从浏览器兼容到生产构建优化均有体现。阅读源码可掌握 Vue Router 页面组织、请求封装和多路视频流布局思路节省从零搭建播控界面的时间。1. RTSP 转 FLV 播放场景EasyMedia-ui 到底是什么一个实际问题某公司要把十几个监控摄像头画面搬到浏览器里刷新页面就能看不用再装厂商的客户端。摄像头那边只有 RTSP 流浏览器里却放不了 RTSP必须在中间加一个服务把 RTSP 拉下来转成 HTTP-FLV 或 HLS再用 flv.js 或普通 video 标签播放。很多人第一反应是自己起 Nginx 做 RTMP 转 HLS结果延迟高、配置绕最后往往被卡在管理界面上——服务起来了却得对着接口文档一行行调。EasyMedia-ui.zip 就是干这个的它是一整套流媒体服务的管理前端把设备接入、通道管理、视频预览、录像回放和后台拉流转发配置整理成可视化页面。这套资源适合两类人一类是有后端基础、想快速交付摄像头直播网页的全栈工程师另一类是刚接触流媒体项目、需要一个能照着改造的前端界面做二次开发的从业者。2. 先拆包再动手目录结构、开发环境与启动配置2.1 解压之后先看哪些目录前端是怎么和后端对接的拿到 EasyMedia-ui.zip别急着 npm install我一般会先看根目录。这个包本质是一个基于 Vue 的前端工程里面通常会有一层 srcsrc 下分 views、api、router、store 等模块。和普通管理后台相比重点要看两个目录src/api 下面的接口定义文件流媒体服务的增删改查、拉流地址获取全部是通过这一层封装出来的后端地址和路径也主要在这里改src/views 下面的 video 或 live 相关页面这是最核心的业务代码通道列表、播放器组件、录像回放入口都在这里。打开 src/api 目录大概率能看到类似这样的文件命名src ├─ api │ ├─ media.ts │ └─ system.ts ├─ views │ ├─ media │ │ ├─ device.vue │ │ ├─ channel.vue │ │ └─ play.vue │ └─ system └─ router把接口文件打开你会看到里面用 axios 封装了一批请求常见做法是统一放在一个 media.js 或 media.ts 文件里访问 /media/channel/list、/media/channel/play 之类的路径。如果你对接的是同一套后端接口路径基本可以直接用如果要对接自己写的服务只需要改 baseURL 和方法路径。这里有个容易出错的地方接口返回的数据结构不同后端风格差异很大。有些返回 { code: 200, data: [...] }有些直接返回数组。拿到包后第一件事不是改页面而是先用接口调试工具或直接浏览器访问一下确认后端返回结构和前端代码里 res.data 的取值是否一致。不一致的话改封装层比改每个页面要省事得多。2.2 开发环境怎么准备npm 版本和依赖装在哪一步容易翻车这个包是前后端分离里的纯前端部分环境准备不复杂。需要本机有 Node.js 和包管理器我用的是 Node 16 左右的 LTS 版本npm install 能顺利跑完。如果你机器上只有最新版 Node遇到旧版 node-sass 类的依赖编译经常会报错这时候不要硬刚直接看 package.json 里的构建脚本换到低版本 Node 再装依赖。装依赖的命令没什么特别cd EasyMedia-ui npm install npm run dev执行完 npm run dev 后终端会输出一个本地访问地址通常是 http://localhost:80 或 http://localhost:8080 之类。这一步理论上很简单但实际翻车概率最高的是两件事。第一件依赖安装时卡在某个二进制包下载表现为进度条卡住不动或报 ECONNRESET。常见原因是 npm 镜像源不稳定解决办法是切换镜像源npm config set registry https://registry.npmmirror.com npm install第二件启动后页面白屏打开控制台看到很多接口 404。这通常是后端起在别的端口而前端代码里写死的接口地址是另一个端口。此时去 src 目录里找到环境变量文件常见是 .env.development 或 src/settings.js把 VITE_PROXY_TARGET 或 baseURL 改成后端实际地址再重启 dev server 就好。2.3 关键配置项这些参数不调后面播放全踩坑开发模式下前端访问后端一般走代理目标地址配置在 vite.config.js 或 webpack 的 proxy 配置里。一个典型的代理配置长这样// vite.config.js export default defineConfig({ server: { host: 0.0.0.0, port: 80, proxy: { /api: { target: http://127.0.0.1:8080, changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ), }, /rtp: { target: http://127.0.0.1:8080, changeOrigin: true, }, }, }, });这里的 /api 是接口层代理/rtp 是流媒体代理。我做这个项目时最常被人问的就是为什么视频预览总是请求一个带 rtp 或 streams 的地址然后一直转圈原因是播放 RTSP 转出来的 FLV 流时后端返回的不一定是静态文件路径而是一个会话型地址比如 http://host:port/rtp/xxx.flv。这类地址需要经过后端转发如果代理没覆盖到浏览器直接请求真实端口能通但页面代码里的 baseURL 会把地址拼成前端域名导致 404。把 /rtp 也加进代理基本能解决大半的播放失败问题。3. 把 RTSP 拉流转成 FLV界面与后端能力的映射3.1 添加摄像头通道的完整流程EasyMedia-ui 这类前端的核心业务是设备管理。设备一般分两层一个是设备对应一台摄像头一个是通道对应设备上的一个视频源。打开前端页面你会看到左侧菜单里大概率有设备管理和通道管理。添加一个摄像头常见路径是设备管理里点新增设备页面会弹一个表单让你填设备名称、设备类型、RTSP 地址、用户名密码等。一个典型 RTSP 地址格式如下rtsp://admin:password192.168.1.64:554/h264/ch1/main/av_stream需要特别说明的是这个字段在后端会直接用于拉流。有一些摄像头在 URL 里带特殊字符比如密码里有 符号必须做 URL 编码否则后端解析地址时会截断到第一个 下面的失败日志里你会看到它把用户名当成了 admin:password 的中间内容怎么都鉴权失败。填完提交前端会调用设备的保存接口。之后页面会显示这条设备的在线状态。有些后端支持通道探测点一下探测通道后端会去尝试连接摄像头返回具体的码流信息前端把通道列表刷新出来。这一步是可选的但不做它后面添加播放地址时只能手填容易填错。我一般会先加一个设备再进通道管理里确认通道状态显示为在线才开始下一步。这一步能帮你把问题定位到拉流失败还是播放失败别上来就去调播放器否则排查范围会大很多。3.2 播放器为什么用 flv.js延迟状态怎么控制在线视频预览页是这个包的核心。打开通道列表右侧会有一个播放按钮点击后弹窗或跳转页面内部是一个 video 标签通过 flv.js 拉取 HTTP-FLV 流进行播放。flv.js 的核心是把 FLV 封装转成 fMP4 喂给浏览器。播放器初始化代码大致是这么写的import flvjs from flv.js; const videoElement document.getElementById(videoPlayer); const flvPlayer flvjs.createPlayer({ type: flv, isLive: true, url: flvUrl, }, { enableStashBuffer: false, stashInitialSize: 128, }); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); flvPlayer.play();这里有两个参数值得单独拿出来讲。enableStashBuffer 设置为 false表示不让播放器自己攒很长一段缓冲再开始播这对低延迟监控场景是必要的。如果保持默认 true你会看到画面总是比现场慢两三秒以上而且时间越长缓冲越厚。stashInitialSize 是初始缓存字节数单位是 KB。网络环境差时可以适当调大但如果是内网128 足够。这个值不是越大越好过度缓存会直接吞掉低延迟优势。哪些参数影响延迟可以看这张表参数作用内网建议值enableStashBuffer是否启用播放器缓冲falsestashInitialSize初始缓存大小KB128isLive是否为直播流trueautoCleanupSourceBuffer是否自动清理缓存片段true我一般习惯先把 stashInitialSize 设成 128实测延迟还不能接受再把 enableStashBuffer 关掉的同时调小 internalBuffer 相关参数。这几个参数在不同版本的 flv.js 里表现略有差异但大方向一致压低缓冲优先级画面延迟下来。3.3 用浏览器控制台验证整条链路是不是通的前端写完、页面也渲染出来了但不能只看画面。我在排查播放问题时候的固定动作是打开浏览器开发者工具切到 Network 面板筛选 Media 类型看那个 .flv 请求的状态码。如果看到 200 且响应体里带上 video/x-flv 或 application/octet-stream说明拉流转发链路是通的问题大概率出在播放器参数或缓冲设置。如果状态码是 404基本是代理没配全或后端流媒体端口没开。如果状态码是 401则是会话鉴权问题看请求头里是否带了 token。再进一步点击那条 flv 请求看响应头是不是没有固定长度或者显示 chunked。HTTP-FLV 直播流是持续输出的正常情况不会有固定 Content-Length。如果显示一个很小的固定长度那后端可能返回的是错误 JSON 而不是流播放器自然起不来。提示如果发现 .flv 请求返回的是文本内容而非二进制流先检查后端拉流日志多半是 RTSP 地址鉴权失败后返回的错误报文。这种报错在前端页面上往往只表现为黑屏或转圈不弹任何提示。用这套方法我能在两分钟内定位一个黑屏是前端缓冲问题还是后端拉流问题而不是瞎调播放器参数。4. 部署与集成从开发机到生产环境的完整落地4.1 打包构建与 nginx 部署细节开发环境调通后下一步就是打包。执行npm run build构建完成后输出目录一般在 dist 下面里面是一个纯静态站点可以丢到任意 Web 服务里。我这里以 nginx 为例最常见的部署做法是新建一个 server 块把 root 指到 dist 目录并为接口和流媒体路径配置反向代理server { listen 80; server_name your-domain; root /opt/easymedia-ui/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; } location /rtp/ { proxy_pass http://127.0.0.1:8080/rtp/; proxy_set_header Host $host; } }在这里try_files 是必须的。因为 Vue Router 用的是 history 模式刷新一个子页面时比如访问 /media/channel如果 nginx 找不到对应的物理文件会直接返回 404加这行配置让它回退到 index.html 就能解决。前端代码里如果写死了 /api 前缀上面的 location /api/ 就能对上。如果开发时用的是 vite 的 rewrite 把 /api 干掉了那部署时要么在 nginx 里也做一层 rewrite要么直接把接口封装层改成不带 /api 的前缀。我自己更倾向保留 /api 前缀让生产环境和开发环境的语义保持一致。4.2 登录鉴权模块的改造套路很多人在拿到这个包后要做的第一件事不是加摄像头而是把它接入公司现有的统一登录体系。这类流媒体管理界面的典型鉴权流程是登录页输入账号密码后端验证后返回 token前端把 token 存起来后续每个请求带上 token 字段或请求头。前端代码里负责这个逻辑的通常是 store 下面的 user 模块和 axios 的拦截器。打开请求封装文件你会看到类似下面的代码axios.interceptors.request.use(config { const token localStorage.getItem(Access-Token); if (token) { config.headers[Authorization] Bearer token; } return config; });如果你要对接自己系统的登录接口只需要改两处。第一处是登录页提交后调用的那个登录接口地址和参数格式第二处是上面这段拦截器里的 token 名称和存放位置要和现有系统保持一致。还有一个小坑跨系统接入时有些系统的 token 不是放在 Authorization 头里而是放在名为 access_token 的 query 参数里。这类接口需要在拦截器里同时处理 query 拼接逻辑。接口层改完页面层的路由守卫也要看一眼beforeEach 里判断没有 token 就重定向到登录页否则会出现一个现象token 过期后页面还停在原处但所有接口都返回 401看起来像系统卡死。4.3 多环境配置环境变量怎么隔离开发、测试、生产生产环境往往不是一套。为了省事我会在 src 下面创建三份环境文件.env.development、.env.test、.env.production定义接口地址、token 名称、日志开关等。构建时通过 --mode 区分npm run build --mode production一个环境文件的示例VITE_APP_BASE_API/api VITE_APP_WS_URLws://your-domain:8080/ws VITE_APP_LOG_ENABLEDfalse前端代码里用 import.meta.env.VITE_APP_BASE_API 读这些变量网络请求封装里统一拼到 baseURL 上。这样做的好处是以后换环境不用重新打包前端构建产物可以复用只要 nginx 或后端网关改一下转发目标就行。有一点要注意如果部署时把前端文件放在 CDN 上接口地址就不要再写相对路径要保证接口指向一个固定的网关域名避免用户拿到页面域名去请求接口域名造成跨域。这类坑在真正上线时才会冒出来开发阶段基本不会暴露。5. 常见问题排查与避坑五条高频翻车记录5.1 flv 黑屏但音频正常甚至整页卡死现象通道播放页面能连上流控制台也没有报 404但 video 画面黑掉偶尔有声音没有图像严重时整个标签页卡顿。原因这不是这个 ui 包独有的问题而是 flv.js 对浏览器版本和视频编码格式的兼容性限制。摄像头输出的 H.265 编码流浏览器原生不支持而 flv.js 大多版本也只完整支持 H.264。后端把 RTSP 转成 FLV 时如果没有把编码转成 H.264浏览器播放端就会挂。解决先确认摄像头输出的视频编码在设备后台把主码流编码改成 H.264子码流同理改不了就在后端转码配置里开启转 H.264但代价是 CPU 占用会上去。如果是 H.264 仍然黑屏就看浏览器是否启用了硬件解码关掉硬件加速再试。5.2 RTSP 地址里带特殊字符导致设备一直离线现象新增设备填完 RTSP 地址保存后通道状态始终是离线后端日志看不到明显的连接错误只有解析异常。原因密码或用户名里包含 、:、/ 这类 URL 保留字符后端解析 rtsp 地址时直接按字符串处理把保留字符截断或解析错了位置导致拉流地址根本不是你想填的那个。解决填地址前先把用户名密码部分做 URL 编码比如密码本来是 abc123在地址里写成 abc%40123。在页面提交前加一个校验函数把 和 : 自动编码能省掉后面大量的拉流排查时间。5.3 点击录像回放白屏接口返回 404现象预览正常但点录像回放时弹窗空白打开 Network 面板看到一个回放接口 404。原因录像回放依赖后端录像模块很多部署方案默认没开启录像存储路径或者回放地址和预览地址用的是不同的代理前缀比如预览是 /rtp回放是 /record而 nginx 或 vite 代理里只配了 /rtp。解决先请求后端接口确认录像文件真实存在如果存在就把 /record 之类的前缀补进代理配置。如果不存在检查后端的录像配置确认 record 路径有存储权限并且已经写入 FLV 或 MP4 文件。这个问题我遇到过不止一次每次都是代理前缀漏配而不是前端页面写错。5.4 登录成功后页面反复跳回登录页现象登录接口正常返回token 也存到了 localStorage但路由守卫仍把用户弹回登录页形成死循环。原因前端把 token 存到了 localStorage但路由守卫或 axios 拦截器读取时用的是 sessionStorage或者是大小写不一致。也有一种可能是 token 过期时间太短后端返回的有效期不到一分钟校验随即失败页面刚跳转就又被弹回登录页。解决统一 token 读写位置和 key建议定义成一个单独模块比如 src/utils/auth.js所有页面和拦截器都从这里读不各自直接操作 localStorage。对于后端 token 有效期极短的情况在响应拦截器里判断 401 时不要急着清 token而是先刷新 token只有刷新失败才跳登录页。5.5 配置改了但页面不生效像被缓存住一样现象改了前端页面里的某个文案或接口地址重新刷新页面还是旧内容甚至 npm run build 之后再访问还是旧版本。原因浏览器对静态资源做了强缓存前端页面文件名如果没带 hash旧版本会被浏览器直接命中或者 nginx 端返回了没有 Cache-Control 的默认缓存策略。解决构建工具默认生成带 hash 的静态文件名关键是要在 nginx 里给 index.html 设置 no-cache同时给带 hash 的资源设置长缓存location /index.html { add_header Cache-Control no-cache, no-store, must-revalidate; } location ~* \.(js|css|png|jpg)$ { add_header Cache-Control public, max-age31536000; }按这个配置后每次发布只需让用户强制刷新一次后续不会再遇到旧版缓存顽固不更新的情况。发布新版本时我一般会在构建机上加一步上传前清空 dist 目录避免遗留旧文件造成新旧资源混合加载。6. 进阶给通道管理加一个独立的审核预览权限当你把整个界面跑通以后最值得动手的改造是给流媒体页面加一层业务权限。很多实际项目里不是所有用户都能看所有摄像头比如某个平台账号只能看某几个通道甚至连通道列表都不应该出现。前端如果只是通过隐藏按钮来应付很不安全因为接口是可以直接访问的。我建议做一个通道授权模块在用户表或角色表里增加一个 channelIds 字段保存允许该用户观看的通道 ID 列表。后端在返回通道列表和拉流地址时都按这个列表过滤。前端要做的事情则比较简单在路由跳转到通道详情时先请求一次用户可访问通道接口用返回结果去控制播放按钮的 disabled 状态和路由守卫router.beforeEach(async (to, from, next) { if (to.meta.requiresPermission) { const accessible await fetch(/api/user/channel-ids); if (!accessible.includes(to.params.channelId)) { next(/403); return; } } next(); });注意这种前端权限校验只是体验层的兜底真正的安全边界必须由后端拉流接口去校验否则直接拿 flv 地址就能播放。做完这个改造以后我每次接新的流媒体界面项目都会强制自己走一遍完整流程先加一个真实设备、发起拉流、再刷新页面验证状态、最后查看接口返回的权限列表。这套动作下来能避免交付给客户后反复出问题。如果你也拿到这份 EasyMedia-ui.zip 做流媒体界面建议别急着改业务先把播放链路整体跑通。希望这些经验能帮到你少走几步弯路。本文还有配套的精品资源点击获取
RELATED

相关推荐

PyTorch线性回归实战:从数据构造到训练闭环

PyTorch线性回归实战:从数据构造到训练闭环

1. 线性回归在深度学习里的位置,以及为什么选它练手很多人刚开始接触 PyTorch,容易被各种名词劝退:反向传播、优化器、损失函数、张量……每一个听起来都像一座山。但如果你真正跑通一个线性回归模型,回头再看这些概念&#xff0c…

📅 2026/10/21 13:47:28
REA分析框架:识别、评估、执行三步法提升效率

REA分析框架:识别、评估、执行三步法提升效率

1. 从“rea”这个标题说起:一个被低估的缩写背后藏着什么 第一次看到“rea”这三个字母,大多数人脑子里蹦出来的第一反应可能是“real”的简写,或者是某个品牌、某个项目的代号。我在几个技术社区和效率工具圈子里泡了挺长时间,发…

📅 2026/10/21 13:47:28
AI Agent记忆持久化实战:FileSystem中间件如何实现跨会话状态恢复

AI Agent记忆持久化实战:FileSystem中间件如何实现跨会话状态恢复

做AI Agent开发的朋友,一定都遇到过这个场景:对话窗口一关,agent就“失忆”了。刚才聊了一半的需求、已经确认好的用户偏好、写到一半的分析流程,界面一刷新全没了。这个问题在LangChain生态里,尤其是用到DeepAgents这…

📅 2026/10/21 13:47:28
MORE NEWS

更多资讯

📰

Python+OpenAI API:从零构建带记忆的聊天机器人实战

我第一次尝试用 Python 调用 OpenAI API 做聊天机器人的时候,心态特别简单:只要能发一句话过去,得到一句回复,就算成功了。可真上了手才发现,很多教程只告诉你调用接口那三五行代码,却不会告诉你上下文怎么…

📰

10月25日:Windows XP、编程语言先驱与通信巨头如何塑造计算史

1. 三个改变计算史的时刻为何落在同一天10 月 25 日这个日期,在计算机发展的时间轴上密集地叠着三件事:一款统治了个人计算近二十年的操作系统正式面向大众发售,一位后来深刻影响全球通信设备格局的企业创始人出生,一位奠定编程语…

📰

lingbot-map:从原始地理数据到交互地图的加工流水线

lingbot-map这个名字,乍一看像是某个聊天机器人插件附带的子模块,但它本质上是一个独立的地图数据加工与发布工具。我自己第一次接触这个项目时,是接到一个模拟项目X的需求:需要在最短时间内把一份杂乱的路网Excel和一批POI点数据…

📰

大模型高级微调实战:从LoRA参数配置到训练评估的完整指南

坦白说,第一次接触“task05高级微调技术”这个任务时,我脑子里闪过一长串疑问:为什么还要专门做微调?直接在提示词里写清楚要求不行吗?训练数据和GPU从哪来?等到自己动手跑完一轮完整的微调流程之后&#x…

📰

MBENET驱动实战:Modbus RTU转TCP网关配置与避坑指南

简介:MBENET驱动是一套面向工业自动化与Modbus TCP通信开发的驱动组件,适合需要将设备接入以太网、实现PLC、HMI等支持Modbus协议设备间数据交换的开发者与运维人员使用。资源包共101个文件,以42个dll动态库、19个exe可执行程序、10个chm帮助…

📰

AIGC检测中的困境度:为何AI概率之外更需关注模型纠结度

1. 困境度指标到底在衡量什么先聊一个特别常见的场景:你把一段文本扔进AIGC检测工具,页面右侧跳出两行结果,一行写着“AI生成概率:78%”,另一行写着“困境度:0.31”。大部分人的视线会被78%带走&#xff0c…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬