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