如何从React前端传递用户输入的RTSP地址到Node端rtsp-relay服务
实现方案
完全可以实现前端动态传入RTSP地址的需求,不需要额外用fetch发HTTP请求传地址,利用rtsp-relay本身支持的动态url配置能力,在建立WebSocket流连接时把用户输入的地址当参数传给服务端即可,实现逻辑比单独发fetch更简洁。
核心原理
rtsp-relay的proxy配置项中,url字段支持传入函数格式,函数可以读取当前WebSocket请求的上下文信息,动态返回要代理的RTSP地址,刚好适配动态传入地址的场景。
作者文档原文翻译:
url配置支持传入(req) => string格式的函数,每次有新的WebSocket连接请求时,都会执行该函数获取实际要代理的RTSP流地址,可用于多摄像头切换、动态地址透传等场景。
服务端改造(Express)
把原来硬编码的url改成动态从请求query中读取的函数,同时增加基础的合法性校验,避免非法请求:
const express = require('express'); const app = express(); const { proxy, scriptUrl } = require('rtsp-relay')(app); const streamProxy = proxy({ url: (req) => { // 解析WS请求携带的query参数 const reqUrl = new URL(req.url, `http://${req.headers.host}`); const rtspAddress = reqUrl.searchParams.get('rtspUrl'); // 基础校验:必须是rtsp协议开头的合法地址 if (!rtspAddress || !rtspAddress.startsWith('rtsp://')) { throw new Error('请传入合法的RTSP流地址'); } return rtspAddress; }, verbose: false, transport: 'tcp', }); // 注册WS代理路由 app.ws('/api/stream', streamProxy); app.get('/', (req, res) => res.send('hg')); app.listen(5000);
前端改造(React + Material-UI)
不需要额外发fetch请求,用户在输入框填写地址提交后,把地址编码后拼接到WebSocket流地址上,重新建立流连接即可:
import React, { useState, useEffect, useRef } from 'react'; // 保留你原来的Box/FormGroup/FormControl/TextField/Button/Close/Trans等导入 const RtspPlayer = () => { // 输入框绑定的临时地址 const [inputUrl, setInputUrl] = useState(''); // 当前实际播放的RTSP地址 const [activeUrl, setActiveUrl] = useState(''); const playerRef = useRef(null); // 输入框值更新 const handleChange = (e) => { setInputUrl(e.target.value); }; // 表单提交:确认使用输入的地址播放 const handleSubmit = (e) => { e.preventDefault(); if (!inputUrl.startsWith('rtsp://')) { alert('请输入rtsp://开头的合法流地址'); return; } setActiveUrl(inputUrl); }; // 监听activeUrl变化,重新加载流 useEffect(() => { if (!activeUrl || !playerRef.current) return; // 编码RTSP地址,避免特殊字符(@/?/&等)导致参数解析错误 const wsUrl = `ws://${window.location.host}/api/stream?rtspUrl=${encodeURIComponent(activeUrl)}`; // 这里替换成你原来硬编码地址能正常播放的逻辑,把WS地址换成上面的wsUrl即可 // 比如rtsp-relay官方示例里的JSMpeg播放器初始化逻辑 new JSMpeg.Player(wsUrl, { canvas: playerRef.current }); }, [activeUrl]); return ( <> {/* 流播放画布 */} <canvas ref={playerRef} /> <Box> <form onSubmit={handleSubmit}> <div> <Box> <Button onClick={() => setActiveUrl('')} aria-label="close-settings-popup"> <Close /> </Button> </Box> </div> <FormGroup> <Box> <FormControl> <TextField type="text" id="rtsp-url" value={inputUrl} onChange={handleChange} label={<Trans i18nKey="form.cameraForm.source">RTSP地址</Trans>} /> </FormControl> </Box> </FormGroup> <div> <Button type="submit" variant="contained" color="primary"> 确认播放 </Button> </div> </form> </Box> </> ); }; export default RtspPlayer;
补充说明
- 如果你坚持想用fetch传地址也可以实现,但属于冗余逻辑:需要先通过POST请求把地址发给服务端存在session/内存中,WS连接时再从服务端存储里读取,会多一次不必要的HTTP请求,还需要处理会话匹配问题,没有任何优势。
- 服务端必须做地址校验:除了校验rtsp协议头,生产环境建议加IP白名单限制,避免被恶意利用发起内网请求(SSRF风险)。
- 拼接WS地址时必须用
encodeURIComponent编码RTSP地址,否则地址中携带的账号密码、路径参数会被错误截断,导致代理失败。
内容的提问来源于stack exchange,提问作者walee
相关产品推荐
相关产品推荐

