wim15013442181 2023-07-09 23:17 采纳率: 36.4%
浏览 94
已结题

websocket跨域对接问题,springboot后端和nodejs后端,vue前端

客户管理系统是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是打开的。

最后能帮向日葵远程调试

  • 写回答

6条回答 默认 最新

  • 「已注销」 2023-07-10 00:03
    关注

    基于new bing部分指引作答:
    根据您提供的代码和描述,我注意到可能存在以下问题:

    跨域配置错误:在您的Node.js后端代码中,使用了cors模块来处理跨域请求,但是您定义的corsOptions中的origin值是ws://localhost:8888/wim。然而,WebSocket的跨域配置应该使用Access-Control-Allow-Origin标头来处理,而不是origin字段。您可以尝试修改corsOptions为以下内容:

    const corsOptions = {
      origin: 'http://localhost:8001', // 更新为正确的Vue前端地址
      methods: ['GET', 'POST'],
      allowedHeaders: ['Content-Type'],
    };
    

    然后,在app.use(cors(corsOptions))之前添加以下代码:

    app.use((req, res, next) => {
      res.header('Access-Control-Allow-Origin', corsOptions.origin);
      res.header('Access-Control-Allow-Headers', corsOptions.allowedHeaders.join(', '));
      next();
    });
    

    这样设置可以确保WebSocket连接的跨域配置正确。

    调用ws.send()的时机不正确:在您的前端Vue代码中,您在WebSocket的open事件中发送了startProxy消息。但是,此时WebSocket连接可能还没有完全建立。正确的做法是在open事件之后的onopen回调中发送消息。您可以尝试修改如下:

    this.socket.onopen = () => {
      // 在连接打开时执行的代码
      console.log('WebSocket connection opened');
      // 发送请求告诉服务器开始代理RTSP流
      this.socket.send('startProxy');
      //this.socket.send(JSON.stringify('startProxy'));
    };
    

    通过这种方式,您可以确保在WebSocket连接完全建立后再发送消息。

    端口代理配置错误:在您提供的端口代理配置文件中,缺少了一个引号,导致wim的配置不完整。请将以下行:

    wim: 'http://localhost:8888/wim
    

    改为:

    wim: 'http://localhost:8888/wim',
    

    这样可以修正配置错误。

    请尝试按照上述修改建议进行调整,看看问题是否得到解决。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 7月15日
  • 创建了问题 7月9日

悬赏问题

  • ¥20 如何在 rocky9.4 部署 CDH6.3.2?
  • ¥35 navicat将excel中的数据导入mysql出错
  • ¥15 rt-thread线程切换的问题
  • ¥20 python忆阻器数字识别
  • ¥15 高通uboot 打印ubi init err 22
  • ¥20 PDF元数据中的XMP媒体管理属性
  • ¥15 R语言中lasso回归报错
  • ¥15 网站突然不能访问了,上午还好好的
  • ¥15 有没有dl可以帮弄”我去图书馆”秒选道具和积分
  • ¥15 semrush,SEO,内嵌网站,api