|
@@ -5,9 +5,12 @@ 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 configPath = process.env.CONFIG_PATH || './runtime-config.json';
|
|
|
+const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
|
+//const ROOT = path.join(__dirname, 'dist', 'h5');
|
|
|
+const PORT = config["local-port"];
|
|
|
+const REMOTE = config["remote-host"];//'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' };
|
|
|
|
|
@@ -43,42 +46,42 @@ function proxyToRemote(req, res) {
|
|
|
|
|
|
/* ------- 静态文件服务函数 ------- */
|
|
|
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');
|
|
|
+ const parsed = url.parse(req.url, true);
|
|
|
+ let pathname = parsed.pathname;
|
|
|
+
|
|
|
+ // 默认索引
|
|
|
+ if (pathname === '/') pathname = '/index.html';
|
|
|
+
|
|
|
+ // 安全限制:禁止跳出 static
|
|
|
+ const safePath = path.normalize(decodeURIComponent(pathname));
|
|
|
+ const STATIC_DIR = path.resolve(config.staticPath || './static');
|
|
|
+ const filePath = path.join(STATIC_DIR, safePath);
|
|
|
+ if (!filePath.startsWith(STATIC_DIR)) {
|
|
|
+ res.statusCode = 403;
|
|
|
+ res.end('Forbidden');
|
|
|
+ return;
|
|
|
+ }
|
|
|
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');
|
|
|
+ if (err.code === 'ENOENT') {
|
|
|
+ res.statusCode = 404;
|
|
|
+ res.end('Not Found');
|
|
|
+ } else {
|
|
|
+ res.statusCode = 500;
|
|
|
+ res.end('Internal Server Error');
|
|
|
+ }
|
|
|
return;
|
|
|
}
|
|
|
- const ext = path.extname(filePath);
|
|
|
- res.writeHead(200, { 'Content-Type': mime[ext] || 'application/octet-stream' });
|
|
|
+
|
|
|
+ const ext = path.extname(filePath).toLowerCase();
|
|
|
+ res.setHeader('Content-Type', mime[ext] || 'application/octet-stream');
|
|
|
res.end(data);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
/* ------- 主入口 ------- */
|
|
|
+
|
|
|
http.createServer((req, res) => {
|
|
|
- // 处理日志请求--纪录
|
|
|
- if (req.method === 'POST' && req.url === '/log') {
|
|
|
- let body = '';
|
|
|
- req.on('data', chunk => body += chunk);
|
|
|
- req.on('end', () => {
|
|
|
- try {
|
|
|
- const { level, msg } = JSON.parse(body);
|
|
|
- writeLog(level, msg);
|
|
|
- } catch { }
|
|
|
- res.writeHead(204);
|
|
|
- res.end();
|
|
|
- });
|
|
|
- return;
|
|
|
- }
|
|
|
// 1. 预检直接 200
|
|
|
if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return; }
|
|
|
|