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}`); });