|
@@ -0,0 +1,76 @@
|
|
|
|
+// server.js —— 零依赖反向代理版
|
|
|
|
+const http = require('http');
|
|
|
|
+const https = require('https');
|
|
|
|
+const fs = require('fs');
|
|
|
|
+const path = require('path');
|
|
|
|
+const url = require('url');
|
|
|
|
+
|
|
|
|
+const ROOT = path.join(__dirname, 'dist', 'h5');
|
|
|
|
+const PORT = process.env.PORT || 3000;
|
|
|
|
+const REMOTE = 'http://101.43.219.60:7700';
|
|
|
|
+
|
|
|
|
+const mime = { '.html': 'text/html', '.js': 'application/javascript', '.css': 'text/css', '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpeg', '.gif': 'image/gif', '.svg': 'image/svg+xml', '.ico': 'image/x-icon' };
|
|
|
|
+
|
|
|
|
+/* ------- 代理函数 ------- */
|
|
|
|
+function proxyToRemote(req, res) {
|
|
|
|
+ const parsed = url.parse(req.url); // /dr/xxx?query
|
|
|
|
+ const path = parsed.path;
|
|
|
|
+ const target = url.parse(REMOTE);
|
|
|
|
+ const options = {
|
|
|
|
+ hostname: target.hostname,
|
|
|
|
+ port: target.port || (target.protocol === 'https:' ? 443 : 80),
|
|
|
|
+ path: path + (parsed.search || ''),
|
|
|
|
+ method: req.method,
|
|
|
|
+ headers: { ...req.headers } // 原样带过去
|
|
|
|
+ };
|
|
|
|
+ // 删除本地头,避免 host 不匹配
|
|
|
|
+ delete options.headers.host;
|
|
|
|
+ delete options.headers.origin;
|
|
|
|
+ delete options.headers.referer;
|
|
|
|
+
|
|
|
|
+ console.log('Options:', options);
|
|
|
|
+ console.log('Path:', options.path);
|
|
|
|
+ const proxyReq = (target.protocol === 'https:' ? https : http).request(options, (proxyRes) => {
|
|
|
|
+ // 把远端响应头原样写给浏览器
|
|
|
|
+ res.writeHead(proxyRes.statusCode, proxyRes.headers);
|
|
|
|
+ proxyRes.pipe(res);
|
|
|
|
+ }).on('error', e => {
|
|
|
|
+ console.error('[proxy error]', e.message);
|
|
|
|
+ res.writeHead(502).end('Bad Gateway');
|
|
|
|
+ });
|
|
|
|
+ req.pipe(proxyReq); // 把浏览器发来的 body 也转发过去
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* ------- 静态文件服务函数 ------- */
|
|
|
|
+function serveStatic(req, res) {
|
|
|
|
+ let file = decodeURIComponent(req.url.split('?')[0]);
|
|
|
|
+ file = file === '/' ? '/index.html' : file;
|
|
|
|
+ const filePath = path.join(ROOT, file);
|
|
|
|
+ if (!filePath.startsWith(ROOT)) return res.writeHead(403).end('Forbidden');
|
|
|
|
+ fs.readFile(filePath, (err, data) => {
|
|
|
|
+ if (err) {
|
|
|
|
+ if (file !== '/index.html') {
|
|
|
|
+ fs.readFile(path.join(ROOT, 'index.html'), (e, d) => {
|
|
|
|
+ if (e) return res.writeHead(500).end('Server Error');
|
|
|
|
+ res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(d);
|
|
|
|
+ });
|
|
|
|
+ } else res.writeHead(404).end('Not Found');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ const ext = path.extname(filePath);
|
|
|
|
+ res.writeHead(200, { 'Content-Type': mime[ext] || 'application/octet-stream' });
|
|
|
|
+ res.end(data);
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* ------- 主入口 ------- */
|
|
|
|
+http.createServer((req, res) => {
|
|
|
|
+ // 1. 预检直接 200
|
|
|
|
+ if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return; }
|
|
|
|
+
|
|
|
|
+ // 2. 路径以 /dr 开头 → 代理
|
|
|
|
+ if (req.url.startsWith('/dr')) { proxyToRemote(req, res); return; }
|
|
|
|
+
|
|
|
|
+ // 3. 其它 → 静态文件
|
|
|
|
+ serveStatic(req, res);
|
|
|
|
+}).listen(PORT, () => console.log(`> H5 running at http://localhost:${PORT}`));
|