fix: dplayer can not playing

This commit is contained in:
2026-03-23 18:08:59 +08:00
parent 08ae7414d0
commit 970aae1c5f
8 changed files with 1117 additions and 1120 deletions

237
proxy.js
View File

@@ -1,113 +1,124 @@
import express from 'express'; import express from 'express';
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import { URL } from 'url'; import { URL } from 'url';
const app = express(); const app = express();
const port = 3000; const port = 3000;
// 允许跨域请求 // 允许跨域请求
app.use((req, res, next) => { app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS'); res.header('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Range'); res.header('Access-Control-Allow-Headers', 'Range');
next(); next();
}); });
// 通用代理路由 // 本地静态文件代理:/local -> C:\Users\xyf17\Merlin\data
app.get('/proxy', async (req, res) => { const localDataPath = 'C:\\Users\\xyf17\\Merlin\\data';
console.log('Received Range header:', req.headers.range); app.use('/local', express.static(localDataPath));
// 获取目标 URL
const targetUrl = req.query.url; // 通用代理路由
console.log('Fetching data from:', targetUrl); app.get('/proxy', async (req, res) => {
if (!targetUrl) { console.log('Received Range header:', req.headers.range);
return res.status(400).json({ error: 'URL parameter is required' }); // 获取目标 URL
} const targetUrl = req.query.url;
console.log('Fetching data from:', targetUrl);
try { if (!targetUrl) {
// 设置请求头 return res.status(400).json({ error: 'URL parameter is required' });
const headers = { }
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}; try {
if (req.headers.range) { // 设置请求头
headers['Range'] = req.headers.range; // 转发 Range 请求头,支持视频分段加载 const headers = {
} 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
};
// 向目标 URL 发起请求
const response = await fetch(targetUrl, { headers }); // 避免上游压缩导致 Range/MSE 解析异常mp4 一般不会压缩,但这里保守处理)
headers['Accept-Encoding'] = 'identity';
// 检查响应状态
if (!response.ok) { if (req.headers.range) {
return res.status(response.status).json({ headers['Range'] = req.headers.range; // 转发 Range 请求头,支持视频分段加载
error: `Failed to fetch: ${response.statusText}`, }
status: response.status
}); // 向目标 URL 发起请求
} const response = await fetch(targetUrl, { headers });
// 设置响应头 // 检查响应状态
response.headers.forEach((value, key) => { if (!response.ok) {
// 跳过一些可能导致问题的头信息 return res.status(response.status).json({
if (key.toLowerCase() !== 'content-encoding' && error: `Failed to fetch: ${response.statusText}`,
key.toLowerCase() !== 'transfer-encoding' && status: response.status
key.toLowerCase() !== 'connection') { });
res.setHeader(key, value); }
}
}); // 关键Range 请求上游通常返回 206必须把状态码透传给浏览器
res.status(response.status);
// 特殊处理 Transfer-Encoding 和 Content-Length
if (response.headers.get('transfer-encoding') === 'chunked') { // 设置响应头
res.removeHeader('Content-Length'); response.headers.forEach((value, key) => {
} // 跳过一些可能导致问题的头信息
if (key.toLowerCase() !== 'content-encoding' &&
// 将响应体直接流式传输给客户端 key.toLowerCase() !== 'transfer-encoding' &&
if (response.body) { key.toLowerCase() !== 'connection') {
response.body.pipe(res, { end: true }); res.setHeader(key, value);
}
// 错误处理 });
response.body.on('error', (err) => {
console.error('Error during data transfer:', err); // 特殊处理 Transfer-Encoding 和 Content-Length
if (!res.headersSent) { if (response.headers.get('transfer-encoding') === 'chunked') {
res.status(500).json({ error: 'Error during data transfer' }); res.removeHeader('Content-Length');
} }
});
} else { // 将响应体直接流式传输给客户端
res.status(500).json({ error: 'No response body' }); if (response.body) {
} response.body.pipe(res, { end: true });
} catch (error) {
console.error('Error fetching data:', error); // 错误处理
response.body.on('error', (err) => {
// 根据错误类型返回更具体的错误信息 console.error('Error during data transfer:', err);
let errorMessage = 'Error fetching data'; if (!res.headersSent) {
let statusCode = 500; res.status(500).json({ error: 'Error during data transfer' });
let hostname = ''; }
});
try { } else {
hostname = new URL(targetUrl).hostname; res.status(500).json({ error: 'No response body' });
} catch (e) { }
hostname = 'unknown'; } catch (error) {
} console.error('Error fetching data:', error);
if (error.code === 'ENOTFOUND') { // 根据错误类型返回更具体的错误信息
errorMessage = `DNS解析失败无法解析域名 "${hostname}"。请检查URL是否正确或网络连接是否正常。`; let errorMessage = 'Error fetching data';
statusCode = 502; let statusCode = 500;
} else if (error.code === 'ECONNREFUSED') { let hostname = '';
errorMessage = `连接被拒绝:无法连接到目标服务器 "${hostname}"。`;
statusCode = 502; try {
} else if (error.code === 'ETIMEDOUT') { hostname = new URL(targetUrl).hostname;
errorMessage = `请求超时:目标服务器 "${hostname}" 响应时间过长。`; } catch (e) {
statusCode = 504; hostname = 'unknown';
} }
if (!res.headersSent) { if (error.code === 'ENOTFOUND') {
res.status(statusCode).json({ errorMessage = `DNS解析失败无法解析域名 "${hostname}"。请检查URL是否正确或网络连接是否正常。`;
error: errorMessage, statusCode = 502;
code: error.code, } else if (error.code === 'ECONNREFUSED') {
targetUrl: targetUrl errorMessage = `连接被拒绝:无法连接到目标服务器 "${hostname}"。`;
}); statusCode = 502;
} } else if (error.code === 'ETIMEDOUT') {
} errorMessage = `请求超时:目标服务器 "${hostname}" 响应时间过长。`;
}); statusCode = 504;
}
app.listen(port, () => {
console.log(`Proxy server running at http://localhost:${port}`); if (!res.headersSent) {
}); res.status(statusCode).json({
error: errorMessage,
code: error.code,
targetUrl: targetUrl
});
}
}
});
app.listen(port, () => {
console.log(`Proxy server running at http://localhost:${port}`);
});

View File

@@ -1,67 +1,93 @@
import { userInfoStore } from "@/store/user"; import { userInfoStore } from "@/store/user";
import axios from "axios"; import axios from "axios";
const userinfo = userInfoStore(); const userinfo = userInfoStore();
export const searchPlayRoom = async (inputValue: string) => { export const searchPlayRoom = async (inputValue: string) => {
const response = await axios.post('/api/playroom/search',{ const response = await axios.post('/api/playroom/search',{
r_name: inputValue r_name: inputValue
},{ },{
headers:{ headers:{
'Authorization': "Bearer " + userinfo.token 'Authorization': "Bearer " + userinfo.token
} }
}) })
if(response.data.code === "200"){ if(response.data.code === "200"){
return response.data.data.records return response.data.data.records
} else { } else {
console.error(response.data.msg) console.error(response.data.msg)
return [] return []
} }
} }
export const createPlayroom = async (room_name: string) => { export const createPlayroom = async (room_name: string) => {
const response = await axios.post('/api/playroom/create',{ const response = await axios.post('/api/playroom/create',{
r_name: room_name r_name: room_name
},{ },{
headers:{ headers:{
'Authorization': "Bearer " + userinfo.token 'Authorization': "Bearer " + userinfo.token
} }
}) })
if(response.data.code === "200"){ if(response.data.code === "200"){
return true; return true;
} else { } else {
throw new Error(response.data.message); throw new Error(response.data.message);
} }
} }
export const getPlayrooms = async ()=> { export const getPlayrooms = async ()=> {
const response = await axios.get('/api/playroom/get',{ const response = await axios.get('/api/playroom/get',{
headers:{ headers:{
'Authorization' : `Bearer ${userinfo.token}` 'Authorization' : `Bearer ${userinfo.token}`
} }
}) })
if(response.data.code === "200"){ if(response.data.code === "200"){
return response.data.data; return response.data.data;
} else { } else {
throw new Error(response.data.message); throw new Error(response.data.message);
} }
} }
export const joinPlayroom = async (r_id: number) => { export const joinPlayroom = async (r_id: number) => {
const response = await axios.post('/api/inviting/playroom',{ const response = await axios.post('/api/inviting/playroom',{
inviter: userinfo.user.id, inviter: userinfo.user.id,
target: userinfo.user.id, target: userinfo.user.id,
status: 0, status: 0,
room: r_id, room: r_id,
},{ },{
headers:{ headers:{
'Authorization': "Bearer " + userinfo.token 'Authorization': "Bearer " + userinfo.token
} }
}) })
if(response.data.code === "200"){ if(response.data.code === "200"){
return true; return true;
} else { } else {
throw new Error(response.data.message); throw new Error(response.data.message);
} }
}
export const getPlayroomDetails = async (r_id:number) =>{
const response = await axios.get('/api/playroom/detail/'+r_id,{
headers:{
'Authorization': "Bearer " + userinfo.token
}
})
if(response.data.code === "200"){
return response.data.data;
} else {
throw new Error(response.data.message);
}
}
export const getPlayroomMembers = async (r_id: number) => {
const response = await axios.get('/api/playroom/member/'+r_id,{
headers:{
'Authorization': "Bearer " + userinfo.token
}
})
if(response.data.code === "200"){
return response.data.data;
} else {
throw new Error(response.data.message);
}
} }

View File

@@ -1,35 +1,37 @@
@import './base.css'; @import './base.css';
#app { #app {
max-width: 1280px; max-width: 1280px;
/* margin: 0 auto; */ width: 100%;
/* padding: 2rem; */ height: 100%;
font-weight: normal; /* margin: 0 auto; */
} /* padding: 2rem; */
font-weight: normal;
a, }
.green {
text-decoration: none; a,
color: hsla(160, 100%, 37%, 1); .green {
transition: 0.4s; text-decoration: none;
padding: 3px; color: hsla(160, 100%, 37%, 1);
} transition: 0.4s;
padding: 3px;
@media (hover: hover) { }
a:hover {
/* background-color: hsla(160, 100%, 37%, 0.2); */ @media (hover: hover) {
} a:hover {
} /* background-color: hsla(160, 100%, 37%, 0.2); */
}
@media (min-width: 1024px) { }
body {
display: flex; @media (min-width: 1024px) {
place-items: center; body {
} display: flex;
place-items: center;
#app { }
display: grid;
/* grid-template-columns: 1fr 1fr; #app {
padding: 0 2rem; */ display: grid;
} /* grid-template-columns: 1fr 1fr;
} padding: 0 2rem; */
}
}

View File

@@ -1,73 +1,92 @@
import { ref } from "vue"; import { ref } from "vue";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { connectWebSocket, disconnectWebSocket, sendMessage, setIsManualClose } from '@/websocket/roomSocket' import { connectWebSocket, disconnectWebSocket, sendMessage, setIsManualClose } from "@/websocket/roomSocket";
interface PlayroomState { interface PlayroomState {
id: number id: number
r_id: number; r_id: number;
r_name: string; r_name: string;
r_introduction: string; r_introduction: string;
r_avatar: string; r_avatar: string;
role: number; role: number;
} }
interface member {
export const PlayroomStore = defineStore("PlayroomStore", id: number;
() =>{ u_id: string;
const currentPlayroom = ref<PlayroomState>(); u_name: string;
const currentUrl = ref<string>(""); u_avatar: string;
}
const setCurrentPlayroom = (playroom: PlayroomState) => {
currentPlayroom.value = playroom;
} export const PlayroomStore = defineStore("PlayroomStore",
() =>{
const getCurrentPlayroom = () =>{ const currentPlayroom = ref<PlayroomState>();
return currentPlayroom.value; const members = ref<member[]>([]);
} const currentUrl = ref<string>("");
const getCurrentId = () =>{ const setCurrentPlayroom = (playroom: PlayroomState) => {
return currentPlayroom.value?.r_id; currentPlayroom.value = playroom;
} }
const setCurrentUrl = (url: string) => { const getCurrentPlayroom = () =>{
currentUrl.value = url; return currentPlayroom.value;
} }
const clearPlayroom = () => { const getCurrentId = () =>{
currentPlayroom.value = undefined; return currentPlayroom.value?.r_id;
currentUrl.value = ""; }
}
const setCurrentUrl = (url: string) => {
return { currentUrl.value = url;
getCurrentPlayroom, }
getCurrentId,
setCurrentPlayroom, const clearPlayroom = () => {
setCurrentUrl, currentPlayroom.value = null;
clearPlayroom, currentUrl.value = "";
} members.value = [];
}) }
export const videoSocketStore = defineStore("videoSocketStore",{ const addmember = (member: member) => {
state: () => ({ members.value.push(member);
isConnected: false, }
hasGotMessage: false,
id: 0 const getmembers = (page: number, pageSize: number) => {
}), return members.value.slice((page - 1) * pageSize, page * pageSize);
}
actions: {
connect(id: number) {
this.id = id; return {
if (this.isConnected === true) return currentPlayroom,
connectWebSocket(); currentUrl,
this.isConnected = true; setCurrentPlayroom,
}, clearPlayroom,
disconnect() { addmember,
setIsManualClose(true); getmembers,
disconnectWebSocket(); }
this.isConnected = false; })
},
send(message: string) { export const videoSocketStore = defineStore("videoSocketStore",{
sendMessage(JSON.stringify(message)); state: () => ({
} isConnected: false,
} hasGotMessage: false,
}) id: 0
}),
actions: {
connect(id: number) {
this.id = id;
if (this.isConnected === true) return
connectWebSocket(id);
this.isConnected = true;
},
disconnect() {
setIsManualClose(true);
disconnectWebSocket();
this.isConnected = false;
},
send(message: string) {
sendMessage(JSON.stringify(message));
}
}
})

View File

@@ -1,119 +1,119 @@
<template> <template>
<div class="container"> <div class="container">
<el-button @Click="createWindow = true">创建房间</el-button> <el-button @Click="createWindow = true">创建房间</el-button>
<el-table :data="rooms"> <el-table :data="rooms">
<el-table-column label="" prop="r_avatar" width="100"> <el-table-column label="" prop="r_avatar" width="100">
<template #default="scope"> <template #default="scope">
<!-- 使用 el-avatar 组件显示头像 --> <!-- 使用 el-avatar 组件显示头像 -->
<el-avatar :src="rooms[scope.$index].r_avatar" size="large" /> <el-avatar :src="rooms[scope.$index].r_avatar" size="large" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="房间名" prop="r_name"></el-table-column> <el-table-column label="房间名" prop="r_name"></el-table-column>
<el-table-column label="房间ID" prop="r_id"></el-table-column> <el-table-column label="房间ID" prop="r_id"></el-table-column>
<el-table-column label="角色" prop="role"></el-table-column> <el-table-column label="角色" prop="role"></el-table-column>
<el-table-column label="简介" prop="r_introduction"></el-table-column> <el-table-column label="简介" prop="r_introduction"></el-table-column>
<el-table-column label=""> <el-table-column label="">
<template #default="scope"> <template #default="scope">
<el-button @click="goToRoom(scope.row)">进入房间</el-button> <el-button @click="goToRoom(scope.row)">进入房间</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
<el-dialog v-model="createWindow" title="创建房间" style="width: 400px;height: 300px;"> <el-dialog v-model="createWindow" title="创建房间" style="width: 400px;height: 300px;">
<el-form ref="form" :model="formData" label-width="80px" @submit.prevent="createroom"> <el-form ref="form" :model="formData" label-width="80px" @submit.prevent="createroom">
<el-form-item label="房间名" prop="roomName"> <el-form-item label="房间名" prop="roomName">
<el-input v-model="formData.roomName" placeholder="请输入房间名" clearable></el-input> <el-input v-model="formData.roomName" placeholder="请输入房间名" clearable></el-input>
</el-form-item> </el-form-item>
<el-button type="primary" native-type="submit">创建</el-button> <el-button type="primary" native-type="submit">创建</el-button>
</el-form> </el-form>
</el-dialog> </el-dialog>
</template> </template>
<script setup> <script setup>
import { onMounted, reactive, ref } from 'vue' import { onMounted, reactive, ref } from 'vue'
import { PlayroomStore } from '@/store/playroom'; import { PlayroomStore } from '@/store/playroom';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { getPlayrooms, createPlayroom } from '@/api/playroom'; import { getPlayrooms, createPlayroom } from '@/api/playroom';
const roominfo = PlayroomStore() const roominfo = PlayroomStore()
const createWindow = ref(false) const createWindow = ref(false)
const formData = reactive({ const formData = reactive({
roomName: '' roomName: ''
}) })
const rooms = ref([]) const rooms = ref([])
const goToRoom = (r) => { const goToRoom = (r) => {
roominfo.setCurrentPlayroom(r); roominfo.setCurrentPlayroom(r);
// 跳转到房间页面 // 跳转到房间页面
const baseUrl = window.location.origin; const baseUrl = window.location.origin;
const targetUrl = `${baseUrl}/room`; // 替换为你的目标路由 const targetUrl = `${baseUrl}/room?r_id=${r.r_id}`; // 替换为你的目标路由
window.open(targetUrl, "room"); window.open(targetUrl, "room");
}; };
const createroom = async () => { const createroom = async () => {
if (!formData.roomName || formData.roomName.trim() === '') { if (!formData.roomName || formData.roomName.trim() === '') {
ElMessage.error('房间名不能为空') ElMessage.error('房间名不能为空')
return return
} }
try { try {
if(await createPlayroom(formData.roomName)){ if(await createPlayroom(formData.roomName)){
ElMessage.success('创建成功') ElMessage.success('创建成功')
}else{ }else{
ElMessage.error('创建失败') ElMessage.error('创建失败')
} }
formData.roomName = '' formData.roomName = ''
createWindow.value = false createWindow.value = false
rooms.value = await getPlayrooms() rooms.value = await getPlayrooms()
} }
catch (error) { catch (error) {
console.log(error) console.log(error)
} }
} }
const getrooms = async () => { const getrooms = async () => {
try { try {
rooms.value = await getPlayrooms() rooms.value = await getPlayrooms()
} }
catch (error) { catch (error) {
ElMessage.error('获取房间列表失败' + error) ElMessage.error('获取房间列表失败' + error)
} }
} }
onMounted(() => { onMounted(() => {
getrooms() getrooms()
}) })
</script> </script>
<style> <style>
.container { .container {
margin-top: 20px; margin-top: 20px;
width: 800px; width: 800px;
height: 600px; height: 600px;
} }
.profile { .profile {
top: 50px; top: 50px;
left: 100px; left: 100px;
width: 100px; width: 100px;
height: 100px; height: 100px;
border-radius: 50%; border-radius: 50%;
background-color: #fff; background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
} }
.profile img { .profile img {
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: cover; object-fit: cover;
border-radius: 50%; border-radius: 50%;
} }
</style> </style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,149 +1,162 @@
import { ref } from "vue"; import { ref } from "vue";
import { userInfoStore } from "@/store/user"; import { userInfoStore } from "@/store/user";
import { ElMessage } from "element-plus";
import { PlayroomStore } from "@/store/playroom";
// userinfo 实例
// userinfo 实例 const userinfo = userInfoStore();
const userinfo = userInfoStore();
const roomid = ref<number>(0);
// 延迟获取 playroom 实例,避免循环依赖
const getPlayroom = () => {
return PlayroomStore(); // WebSocket 实例
}; const socket = ref<WebSocket | null>(null);
const isManualClose = ref<boolean>(false);
// WebSocket 实例
const socket = ref(null); const reconnectScheduled = ref<boolean>(false);
const isManualClose = ref(false); const retryCount = ref<number>(0);
const reconnectScheduled = ref(false); const getRetryCount = () => {
return retryCount.value;
const retryCount = ref(0); };
export const getRetryCount = () => { const addRetryCount = () => {
return retryCount.value; retryCount.value = retryCount.value + 1;
}; };
export const addRetryCount = () => { const resetRetryCount = () => {
retryCount.value = retryCount.value + 1; retryCount.value = 0;
}; };
const setReconnectScheduled = (value: boolean) => {
export const resetRetryCount = () => { reconnectScheduled.value = value;
retryCount.value = 0; };
};
export const setReconnectScheduled = (value) => { const getReconnectScheduled = () => {
reconnectScheduled.value = value; return reconnectScheduled.value;
}; };
export const getReconnectScheduled = () => { export const setIsManualClose = (value: boolean) => {
return reconnectScheduled.value; isManualClose.value = value;
}; };
export const setIsManualClose = (value) => { const getIsManualClose = () => {
isManualClose.value = value; return isManualClose.value;
}; };
export const getIsManualClose = () => { // 连接WebSocket
return isManualClose.value; export const connectWebSocket = (r_id: number) => {
}; roomid.value = r_id;
const protocol = window.location.protocol === "https:" ? "wss://" : "ws://";
// 连接WebSocket const host = window.location.host;
export const connectWebSocket = () => { const socketUrl = `${protocol}${host}/ws/playroom?r_id=${r_id}`;
const playroom = getPlayroom();
const protocol = window.location.protocol === "https:" ? "wss://" : "ws://"; // const socketUrl = `ws://localhost:8080/online?u_id=${userinfo.user.u_id}&u_name=${userinfo.user.u_name}`;
const host = window.location.host; if (socket.value && socket.value.readyState !== WebSocket.CLOSED) {
const socketUrl = `${protocol}${host}/ws/video?r_id=${playroom.getCurrentId()}`; console.log("还在重连中...");
return;
// const socketUrl = `ws://localhost:8080/online?u_id=${userinfo.user.u_id}&u_name=${userinfo.user.u_name}`; }
if (socket.value && socket.value.readyState !== WebSocket.CLOSED) { const retrytime = getRetryCount();
console.log("还在重连中..."); if (retrytime >= 10) {
return; console.log("重连失败,请稍后再试");
} return;
const retrytime = getRetryCount(); }
if (retrytime >= 10) { console.log(retrytime);
console.log("重连失败,请稍后再试"); socket.value = new WebSocket(socketUrl, "token-"+ userinfo.token);
return;
} socket.value.onopen = (event: any) => {
console.log(retrytime); console.log("WebSocket for video 连接已建立", event);
socket.value = new WebSocket(socketUrl, "token-"+ userinfo.token); setReconnectScheduled(false);
setIsManualClose(false);
socket.value.onopen = (event) => { resetRetryCount();
console.log("WebSocket for video 连接已建立", event); };
setReconnectScheduled(false);
setIsManualClose(false); //处理消息逻辑
resetRetryCount(); socket.value.onmessage = (event) => {
}; console.log("从服务器收到消息:", event.data);
try{
//处理消息逻辑 const MessageData = JSON.parse(event.data);
socket.value.onmessage = (event) => { const cmd = MessageData.cmd;
console.log("从服务器收到消息:", event.data); switch(cmd){
try{ case "PING":
const MessageData = JSON.parse(event.data); console.log("收到PING消息");
const cmd = MessageData.cmd; const msg = {
switch(cmd){ cmd: "PONG",
case "VIDEO_SYNC": from: MessageData.to,
console.log("视频同步消息", MessageData); // 可扩展字段
break; time: new Date().toLocaleString()
} }
}catch(error){ sendMessage(msg);
console.error("解析 JSON 失败:", error); break;
} case "VIDEO_SYNC":
// console.log("视频同步消息", MessageData);
}; break;
}
socket.value.onerror = (error) => { }catch(error){
console.error("WebSocket for video 发生错误", error); console.error("解析 JSON 失败", error);
// console.log(error); }
setReconnectScheduled(true);
socket.value.close(); };
};
socket.value.onerror = (error) => {
socket.value.onclose = (event) => { console.error("WebSocket for video 发生错误:", error);
if (!getIsManualClose()) { // console.log(error);
if (getReconnectScheduled()) { setReconnectScheduled(true);
socket.value = null; socket.value.close();
addRetryCount(); };
setTimeout(reConnectWebSocket, 5000);
setReconnectScheduled(false); socket.value.onclose = (event) => {
} else { if (!getIsManualClose()) {
// console.log("websocket因为浏览器省电设置断开"); if (getReconnectScheduled()) {
console.log("WebSocket for video 连接已关闭", event); socket.value = null;
} addRetryCount();
} setTimeout(reConnectWebSocket, 5000);
}; setReconnectScheduled(false);
}; } else {
// console.log("websocket因为浏览器省电设置断开");
// 断开WebSocket连接 console.log("WebSocket for video 连接已关闭", event);
export const disconnectWebSocket = () => { }
if (socket.value && socket.value.readyState === WebSocket.OPEN) { }
socket.value.close(); };
} };
};
// 断开WebSocket连接
// 重连机制 export const disconnectWebSocket = () => {
export const reConnectWebSocket = () => { if (socket.value && socket.value.readyState === WebSocket.OPEN) {
connectWebSocket(); roomid.value = 0;
}; socket.value.close();
}
// 发送消息 };
export const sendMessage = (message) => {
if (socket.value && socket.value.readyState === WebSocket.OPEN) { // 重连机制
socket.value.send(message); export const reConnectWebSocket = () => {
} else { connectWebSocket(roomid.value);
console.warn("WebSocket for video 未连接,无法发送消息"); };
}
}; // 发送消息
export const sendMessage = (message: any) => {
//没有错误的重连,只是浏览器在后台断开了连接 try{
document.addEventListener("visibilitychange", () => { const jsonmessage = JSON.stringify(message);
if (document.hidden) { if (socket.value && socket.value.readyState === WebSocket.OPEN) {
} else { socket.value.send(jsonmessage);
if (!getIsManualClose() && socket.value.readyState === WebSocket.CLOSED) { } else {
if (getReconnectScheduled()) { console.warn("WebSocket for video 未连接,无法发送消息");
return; }
} }
reConnectWebSocket(); catch(error){
} console.error("Failed to stringify message:", error);
} }
}); };
//没有错误的重连,只是浏览器在后台断开了连接
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
} else {
if (!getIsManualClose() && socket.value.readyState === WebSocket.CLOSED) {
if (getReconnectScheduled()) {
return;
}
reConnectWebSocket();
}
}
});

View File

@@ -29,11 +29,6 @@ export default defineConfig({
changeOrigin: true, changeOrigin: true,
ws: true, ws: true,
}, },
// '/ws': {
// target: 'ws://localhost:8080',
// changeOrigin: true,
// ws: true,
// }
}, },
host: '0.0.0.0', host: '0.0.0.0',
port: 5173, port: 5173,