const http = require('http') const fs = require('fs') const path = require('path') const PORT = 3001 const BACKEND = 'http://127.0.0.1:8583' const STATIC_DIR = path.join(__dirname, 'dist', 'build', 'h5') const API_PREFIX = '/forge-h5-api' const APP_BASE = '/forge-h5' const MIME_TYPES = { '.html': 'text/html; charset=utf-8', '.js': 'application/javascript; charset=utf-8', '.css': 'text/css; charset=utf-8', '.json': 'application/json; charset=utf-8', '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.svg': 'image/svg+xml', '.ico': 'image/x-icon', '.woff': 'font/woff', '.woff2': 'font/woff2', '.ttf': 'font/ttf', '.map': 'application/json', } function getMimeType(filePath) { const ext = path.extname(filePath).toLowerCase() return MIME_TYPES[ext] || 'application/octet-stream' } function proxyRequest(req, res) { const url = req.url.replace(API_PREFIX, '') const options = { hostname: '127.0.0.1', port: 8583, path: url, method: req.method, headers: { ...req.headers, host: '127.0.0.1:8583', }, } const proxyReq = http.request(options, (proxyRes) => { // 复制响应头 const headers = {} for (const [key, value] of Object.entries(proxyRes.headers)) { if (key !== 'transfer-encoding') { headers[key] = value } } res.writeHead(proxyRes.statusCode, headers) proxyRes.pipe(res) }) proxyReq.on('error', (err) => { console.error(`[API Proxy Error] ${req.method} ${url}:`, err.message) res.writeHead(502, { 'Content-Type': 'application/json' }) res.end(JSON.stringify({ error: 'Backend service unavailable' })) }) req.pipe(proxyReq) } function serveStatic(req, res) { let urlPath = req.url // 去掉 /forge-h5 前缀,映射到静态文件目录 if (urlPath.startsWith(APP_BASE)) { urlPath = urlPath.slice(APP_BASE.length) || '/' } let filePath = path.join(STATIC_DIR, urlPath === '/' ? '/index.html' : urlPath) // 安全检查:防止路径遍历 if (!filePath.startsWith(STATIC_DIR)) { res.writeHead(403) res.end('Forbidden') return } fs.readFile(filePath, (err, data) => { if (err) { // SPA 回退:如果文件不存在,返回 index.html fs.readFile(path.join(STATIC_DIR, 'index.html'), (err2, data2) => { if (err2) { res.writeHead(500) res.end('Internal Server Error') return } res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }) res.end(data2) }) return } res.writeHead(200, { 'Content-Type': getMimeType(filePath) }) res.end(data) }) } const server = http.createServer((req, res) => { // API 请求代理到后端 if (req.url.startsWith(API_PREFIX)) { console.log(`[API] ${req.method} ${req.url} -> ${BACKEND}${req.url.replace(API_PREFIX, '')}`) proxyRequest(req, res) } else { // 静态文件服务 console.log(`[Static] ${req.method} ${req.url}`) serveStatic(req, res) } }) server.listen(PORT, '0.0.0.0', () => { console.log(`Server running at http://0.0.0.0:${PORT}`) console.log(`Static files: ${STATIC_DIR}`) console.log(`API proxy: ${API_PREFIX} -> ${BACKEND}`) })