|
|
|
|
/**
|
|
|
|
|
* 开发环境代理服务器
|
|
|
|
|
* 用于解决跨域问题和统一 API 请求
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
const express = require('express');
|
|
|
|
|
const { createProxyMiddleware } = require('http-proxy-middleware');
|
|
|
|
|
const cors = require('cors');
|
|
|
|
|
|
|
|
|
|
const app = express();
|
|
|
|
|
const PORT = 8086;
|
|
|
|
|
|
|
|
|
|
// 启用 CORS
|
|
|
|
|
app.use(cors({
|
|
|
|
|
origin: '*', // 允许所有源,开发环境使用
|
|
|
|
|
credentials: true,
|
|
|
|
|
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'],
|
|
|
|
|
allowedHeaders: [
|
|
|
|
|
'Content-Type',
|
|
|
|
|
'Authorization',
|
|
|
|
|
'X-Requested-With',
|
|
|
|
|
'Accept',
|
|
|
|
|
// 自定义请求头
|
|
|
|
|
'cmdId',
|
|
|
|
|
'datetime',
|
|
|
|
|
'pwds',
|
|
|
|
|
'aseqId',
|
|
|
|
|
'nc',
|
|
|
|
|
'apiName',
|
|
|
|
|
'tid',
|
|
|
|
|
'custId',
|
|
|
|
|
'reqId',
|
|
|
|
|
'isMobileOpen',
|
|
|
|
|
'languageNum',
|
|
|
|
|
'project',
|
|
|
|
|
'platform',
|
|
|
|
|
'checkOr',
|
|
|
|
|
'tbc',
|
|
|
|
|
'reqKey',
|
|
|
|
|
'signature',
|
|
|
|
|
'authorization',
|
|
|
|
|
],
|
|
|
|
|
exposedHeaders: ['cmdId', 'datetime', 'pwds', 'aseqId', 'nc', 'checkOr', 'checkor'],
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
// 目标 API 服务器地址
|
|
|
|
|
const API_TARGET = process.env.API_TARGET || 'https://51zhh5.notbug.org';
|
|
|
|
|
|
|
|
|
|
// 代理路径列表
|
|
|
|
|
const PROXY_PATHS = ['/api/v1', '/api/v2', '/api/v3'];
|
|
|
|
|
|
|
|
|
|
// 为每个路径配置代理
|
|
|
|
|
PROXY_PATHS.forEach((path) => {
|
|
|
|
|
app.use(
|
|
|
|
|
path,
|
|
|
|
|
createProxyMiddleware({
|
|
|
|
|
target: API_TARGET,
|
|
|
|
|
changeOrigin: true,
|
|
|
|
|
secure: false, // 如果目标服务器使用自签名证书,设置为 false
|
|
|
|
|
pathRewrite: (pathStr, req) => {
|
|
|
|
|
// Express 会自动去掉匹配的前缀,所以需要加回来
|
|
|
|
|
const fullPath = path + pathStr;
|
|
|
|
|
console.log(`[Proxy] Path rewrite: ${pathStr} → ${fullPath}`);
|
|
|
|
|
return fullPath;
|
|
|
|
|
},
|
|
|
|
|
onProxyReq: (proxyReq, req, res) => {
|
|
|
|
|
const fullPath = path + req.url;
|
|
|
|
|
console.log(`[Proxy] ${req.method} ${fullPath} → ${API_TARGET}${fullPath}`);
|
|
|
|
|
},
|
|
|
|
|
onProxyRes: (proxyRes, req, res) => {
|
|
|
|
|
const fullPath = path + req.url;
|
|
|
|
|
console.log(`[Proxy] ${req.method} ${fullPath} ← ${proxyRes.statusCode}`);
|
|
|
|
|
|
|
|
|
|
// 确保 CORS 头被正确设置
|
|
|
|
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
|
|
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH');
|
|
|
|
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, Accept, cmdId, datetime, pwds, aseqId, nc, apiName, tid, custId, reqId, isMobileOpen, languageNum, project, platform, checkOr, tbc, reqKey, signature, authorization');
|
|
|
|
|
res.setHeader('Access-Control-Expose-Headers', 'cmdId, datetime, pwds, aseqId, nc, checkOr, checkor');
|
|
|
|
|
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
|
|
|
},
|
|
|
|
|
onError: (err, req, res) => {
|
|
|
|
|
console.error('[Proxy Error]', err.message);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
error: 'Proxy Error',
|
|
|
|
|
message: err.message,
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 健康检查
|
|
|
|
|
app.get('/health', (req, res) => {
|
|
|
|
|
res.json({
|
|
|
|
|
status: 'ok',
|
|
|
|
|
proxy: API_TARGET,
|
|
|
|
|
timestamp: new Date().toISOString(),
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
app.listen(PORT, () => {
|
|
|
|
|
console.log(`
|
|
|
|
|
╔════════════════════════════════════════════════════════╗
|
|
|
|
|
║ 🚀 Proxy Server Running ║
|
|
|
|
|
╠════════════════════════════════════════════════════════╣
|
|
|
|
|
║ Local: http://localhost:${PORT} ║
|
|
|
|
|
║ Target: ${API_TARGET.padEnd(40)} ║
|
|
|
|
|
║ Health: http://localhost:${PORT}/health ║
|
|
|
|
|
╚════════════════════════════════════════════════════════╝
|
|
|
|
|
`);
|
|
|
|
|
});
|