客户管理系统是springboot+vue,包含了http和websocket. springboot 端口80,vue前端端口8001,前端通过代理统一到了localhost:8001端口。
因为需要在前端播放RTSP流,采用了nodejs express+websocket+ffmpeg做后端,把RTSP流转换成flv格式传递到前端。前后端调试,可能是ws前后端跨域可能没处理好,代码如下。
以下是nodejs代码:
"use strict";
const express = require('express');
const http = require('http');
const bodyParser = require('body-parser');
const logger = require('morgan');
const path = require('path');
const colors = require('colors');
const crypto = require('crypto');
const md5 = crypto.createHash('md5');
const dbconfig = require('../dbconfig');
const mysql = require('mysql');
const RtspStream = require('rtsp-stream');
const { spawn } = require('child_process');
const ffmpeg = require('fluent-ffmpeg');
const WebSocket = require('ws');
const cors = require('cors');
const corsOptions = {origin: 'ws://localhost:8888/wim'};
const app = express();
const server = http.createServer(app);
//const wss = new WebSocket.Server({ server });
const wss = new WebSocket.Server({ server, path: '/wim', perMessageDeflate: false, handleProtocols: (protocols) => ['wim'] });
const rtspStreamUrl = 'rtsp://192.168.0.101:8554/test'; // 替换为实际的 RTSP 流地址
//const rtspStreamUrl = 'http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8';
let ffmpegCommand; // 存储 FFmpeg 进程的变量
// 处理客户端的 WebSocket 连接
wss.on('connection', (ws) => {
console.log('wss.on+27');
ws.on('message', (message) => {
console.log('29');
console.log(typeof message, message);
//message转换成String
if (Buffer.isBuffer(message)) {
message = message.toString();
};
console.log(typeof message, message);
if (message === 'startProxy') {
console.log('31')
if (ffmpegCommand) {
// 如果已经有正在运行的 FFmpeg 进程,则结束它
ffmpegCommand.kill();
}
// 创建 FFmpeg 进程,并将 RTSP 转码为 FLV
ffmpegCommand = spawn('ffmpeg', [
'-i', rtspStreamUrl,
'-c:v', 'copy',
'-c:a', 'aac',
'-f', 'flv',
//'-movflags', 'frag_keyframe+empty_moov',
//'pipe:1'
]);
ffmpegCommand.on('start', () => {
console.log('FFmpeg process has started---55');
});
ffmpegCommand.on('error', (err) => {
console.error('FFmpeg error:', err);
ws.send('proxyError'); // Notify the frontend of proxy error
});
ffmpegCommand.on('exit', (code, signal) => {
if (code === 0) {
console.log('FFmpeg process has exited successfully');
} else {
console.error('FFmpeg process has exited with code:', code);
ws.send('proxyError'); // Notify the frontend of proxy error
}
});
ffmpegCommand.stdout.on('data', (data) => {
// You can optionally log the FFmpeg output here
console.log('FFmpeg output:', data.toString());
});
ffmpegCommand.stderr.on('data', (data) => {
// You can optionally log the FFmpeg error output here
console.error('FFmpeg error output:', data.toString());
});
ffmpegCommand.on('close', (code, signal) => {
console.log('FFmpeg process has been closed');
ws.send('proxyEnd'); // Notify the frontend that proxy has ended
});
ffmpegCommand.stdout.pipe(ws); // Pipe FFmpeg stdout to the WebSocket
console.log('64');
ws.send('proxyStarted'); // 通知前端代理已开始
}
});
});
// 静态文件目录
app.use(express.static(path.join(__dirname, 'public')));
// 处理 POST 请求中的 JSON 数据
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// 日志输出
app.use(logger('dev'));
//处理资源跨域,只允许特定域名的请求
app.use(cors(corsOptions));
//n处理客户端的 HTTP 请求
app.get('/stream', (req, res) => {
res.setHeader('Content-Type', 'video/x-flv');
res.send('Please use WebSocket to connect for video streaming.'); // 请使用 WebSocket 连接进行视频流传输
});
const port = 8888; // 你可以修改端口号
server.listen(port, () => {
console.log(`服务器已启动,监听端口 ${port}`);
});
以下是前端VUE页面
<template>
<div>
<video ref="videoElement" controls></video>
</div>
</template>
<script>
import flvjs from 'flv.js';
export default {
data() {
return {
socket: null,
videoElement: null,
flvPlayer: null,
};
},
mounted() {
this.videoElement = this.$refs.videoElement;
// 在视频播放器元素上添加点击事件
// WebSocket代理服务器地址
//const proxyUrl = 'ws://localhost:8001/wim';
const proxyUrl = 'ws://' + window.location.hostname + ':8001/wim'
// 创建WebSocket连接
//this.socket = new WebSocket(proxyUrl);
this.socket = new WebSocket(proxyUrl, 'wim');
//只是为了增加一步,方便看程序
console.log('front-end 32');
if (this.socket.readyState === WebSocket.OPEN) {
console.log('WebSocket 连接已经打开');
} else {
console.log('WebSocket 连接未打开');
};
this.socket.onopen = () => {
// 在连接打开时执行的代码
console.log('WebSocket connection opened');
// 发送请求告诉服务器开始代理RTSP流
this.socket.send('startProxy');
//this.socket.send(JSON.stringify('startProxy'));
};
if (this.socket.readyState === WebSocket.OPEN) {
console.log('WebSocket 连接已经打开');
} else {
console.log('WebSocket 连接未打开');
};
// 当WebSocket连接打开时
this.socket.addEventListener('open', () => {
console.log('WebSocket connection opened');
// 发送请求告诉服务器开始代理RTSP流
this.socket.send('startProxy');
//this.socket.send(JSON.stringify('startProxy'));
});
if (this.socket.readyState === WebSocket.OPEN) {
console.log('WebSocket 连接已经打开');
} else {
console.log('WebSocket 连接未打开');
};
// 当接收到消息时
this.socket.addEventListener('message', (event) => {
console.log('message39');
const message = event.data;
if (message === 'proxyStarted') {
// 代理已开始,使用flv.js播放器播放视频流
if (this.videoElement && flvjs.isSupported()) {
this.flvPlayer = flvjs.createPlayer({
type: 'flv',
//url: 'http://localhost:8001/stream'
//url: 'rtsp://192.168.0.103:8554/test'
url: 'ws://localhost:8001/wim'
});
this.flvPlayer.attachMediaElement(this.videoElement);
this.flvPlayer.load();
this.flvPlayer.play();
this.flvPlayer.on(flvjs.Events.ERROR, (event, data) => {
console.error('FLV.js error:', data);
});
this.flvPlayer.on(flvjs.Events.LOADING_COMPLETE, () => {
console.log('Video loading complete');
});
}
} else if (message === 'proxyError') {
// 代理发生错误
console.error('Proxy error');
} else if (message === 'proxyEnd') {
// 代理已结束
console.log('Proxy ended');
}
});
// 当WebSocket连接错误时
this.socket.addEventListener('error', () => {
console.log('WebSocket connection Error');
});
},
beforeDestroy() {
if (this.socket) {
// 关闭WebSocket连接
this.socket.close();
}
if (this.flvPlayer) {
// 销毁flv.js播放器
this.flvPlayer.unload();
this.flvPlayer.detachMediaElement();
this.flvPlayer.destroy();
}
}
};
</script>
端口代理:
module.exports = {
// 开发环境代理服务器
devProxy: {
host: 'localhost',//'0.0.0.0', // ip/localhost都可以访问
port: 8001
},
// 后端服务器地址
servers: {
proxyApi: 'http://localhost:80/',
//proxyApi: 'http://localhost:8000/',
//ais: 'http://192.168.55.100:8888/ais',
//ais: 'http://192.168.2.100:8000/ais',
ais: 'http://localhost:8888/ais',
//ais: 'http://192.168.177.181:8888/ais',
mysqlRouter:'http://localhost:8888/mysqlRouter',
stream: 'http://localhost:8888/stream',
wim: 'http://localhost:8888/wim
}
}
问题:前端页面调试,前端页面websocket看起来跑了两轮,第一轮并没有正常打开,但是代码过了一遍。第二遍nodejs后端停止运行了,前端websocket是打开的。
最后能帮向日葵远程调试