新增全局开启关闭 mock数据
This commit is contained in:
parent
da026bf306
commit
099fd3c62e
@ -11,6 +11,7 @@
|
|||||||
"#/api2/device/one": "mock/device_detail.txt"
|
"#/api2/device/one": "mock/device_detail.txt"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
|
"mockEnabled": true,
|
||||||
"cacheConfig": true,
|
"cacheConfig": true,
|
||||||
"reloadOnChange": true,
|
"reloadOnChange": true,
|
||||||
"defaultContentType": "application/json",
|
"defaultContentType": "application/json",
|
||||||
|
|||||||
292
index.api.js
Normal file
292
index.api.js
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
"use strict";
|
||||||
|
var __assign = (this && this.__assign) || function () {
|
||||||
|
__assign = Object.assign || function(t) {
|
||||||
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||||
|
s = arguments[i];
|
||||||
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||||
|
t[p] = s[p];
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
return __assign.apply(this, arguments);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
var http = require("http");
|
||||||
|
var https = require("https");
|
||||||
|
var fs = require("fs");
|
||||||
|
var path = require("path");
|
||||||
|
// 配置文件路径
|
||||||
|
var CONFIG_FILE = path.join(__dirname, 'config.json');
|
||||||
|
// 存储当前的路由配置
|
||||||
|
var MOCK_ROUTES = {};
|
||||||
|
var CONFIG = {
|
||||||
|
cacheConfig: true,
|
||||||
|
reloadOnChange: true,
|
||||||
|
defaultContentType: "application/json",
|
||||||
|
proxyPort: 9443,
|
||||||
|
targetHost: "devrmtapp.resmart.cn"
|
||||||
|
};
|
||||||
|
// 过滤掉以 # 开头的路由(视为注释,不参与 mock)
|
||||||
|
function filterActiveRoutes(routes) {
|
||||||
|
var filtered = {};
|
||||||
|
for (var _i = 0, _a = Object.entries(routes); _i < _a.length; _i++) {
|
||||||
|
var _b = _a[_i], route = _b[0], filePath = _b[1];
|
||||||
|
if (route.startsWith('#'))
|
||||||
|
continue;
|
||||||
|
filtered[route] = filePath;
|
||||||
|
}
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
// 加载配置文件
|
||||||
|
function loadConfig() {
|
||||||
|
try {
|
||||||
|
if (!fs.existsSync(CONFIG_FILE)) {
|
||||||
|
console.warn("[CONFIG] \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728: ".concat(CONFIG_FILE));
|
||||||
|
console.warn("[CONFIG] \u6B63\u5728\u521B\u5EFA\u9ED8\u8BA4\u914D\u7F6E\u6587\u4EF6...");
|
||||||
|
// 创建默认配置
|
||||||
|
var defaultConfig = {
|
||||||
|
routes: {
|
||||||
|
"/api2/test": "mock/test.txt"
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
cacheConfig: true,
|
||||||
|
reloadOnChange: true,
|
||||||
|
defaultContentType: "application/json",
|
||||||
|
proxyPort: 9443,
|
||||||
|
targetHost: "devrmtapp.resmart.cn"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 确保mock目录存在
|
||||||
|
var mockDir = path.join(__dirname, 'mock');
|
||||||
|
if (!fs.existsSync(mockDir)) {
|
||||||
|
fs.mkdirSync(mockDir, { recursive: true });
|
||||||
|
}
|
||||||
|
// 保存配置文件
|
||||||
|
fs.writeFileSync(CONFIG_FILE, JSON.stringify(defaultConfig, null, 2), 'utf-8');
|
||||||
|
console.log("[CONFIG] \u5DF2\u521B\u5EFA\u9ED8\u8BA4\u914D\u7F6E\u6587\u4EF6: ".concat(CONFIG_FILE));
|
||||||
|
// 加载配置(# 开头的路由视为注释,不参与 mock)
|
||||||
|
var configData = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
|
||||||
|
MOCK_ROUTES = filterActiveRoutes(configData.routes || {});
|
||||||
|
CONFIG = configData.config || CONFIG;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var configData = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
|
||||||
|
MOCK_ROUTES = filterActiveRoutes(configData.routes || {});
|
||||||
|
CONFIG = configData.config || CONFIG;
|
||||||
|
console.log("[CONFIG] \u914D\u7F6E\u6587\u4EF6\u5DF2\u52A0\u8F7D\uFF0C\u5171 ".concat(Object.keys(MOCK_ROUTES).length, " \u4E2A\u8DEF\u7531").concat(CONFIG.mockEnabled !== false ? '' : '(mock 已关闭,全部走代理)'));
|
||||||
|
}
|
||||||
|
// 验证mock文件是否存在
|
||||||
|
validateMockFiles();
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error("[CONFIG] \u52A0\u8F7D\u914D\u7F6E\u6587\u4EF6\u5931\u8D25:", error);
|
||||||
|
// 使用默认配置
|
||||||
|
MOCK_ROUTES = {
|
||||||
|
"/api2/user/list": "mock/user_list.txt"
|
||||||
|
};
|
||||||
|
CONFIG = {
|
||||||
|
cacheConfig: true,
|
||||||
|
reloadOnChange: true,
|
||||||
|
defaultContentType: "application/json",
|
||||||
|
proxyPort: 9443,
|
||||||
|
targetHost: "devrmtapp.resmart.cn"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 验证mock文件是否存在
|
||||||
|
function validateMockFiles() {
|
||||||
|
console.log("[CONFIG] \u9A8C\u8BC1mock\u6587\u4EF6...");
|
||||||
|
var missingFiles = [];
|
||||||
|
for (var _i = 0, _a = Object.entries(MOCK_ROUTES); _i < _a.length; _i++) {
|
||||||
|
var _b = _a[_i], route = _b[0], filePath = _b[1];
|
||||||
|
var fullPath = path.join(__dirname, filePath);
|
||||||
|
if (!fs.existsSync(fullPath)) {
|
||||||
|
missingFiles.push({ route: route, filePath: filePath, fullPath: fullPath });
|
||||||
|
console.warn("[CONFIG] \u8B66\u544A: mock\u6587\u4EF6\u4E0D\u5B58\u5728 - ".concat(filePath, " (\u7528\u4E8E\u8DEF\u7531: ").concat(route, ")"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (missingFiles.length > 0) {
|
||||||
|
console.log("[CONFIG] \u7F3A\u5C11 ".concat(missingFiles.length, " \u4E2Amock\u6587\u4EF6\uFF0C\u8BF7\u521B\u5EFA\u8FD9\u4E9B\u6587\u4EF6"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log("[CONFIG] \u6240\u6709mock\u6587\u4EF6\u9A8C\u8BC1\u901A\u8FC7");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 检查是否为mock路由的函数
|
||||||
|
function isMockRoute(requestPath) {
|
||||||
|
if (CONFIG.mockEnabled === false)
|
||||||
|
return false;
|
||||||
|
return MOCK_ROUTES.hasOwnProperty(requestPath);
|
||||||
|
}
|
||||||
|
// 获取mock文件路径
|
||||||
|
function getMockFilePath(requestPath) {
|
||||||
|
return MOCK_ROUTES[requestPath];
|
||||||
|
}
|
||||||
|
// 代理服务器
|
||||||
|
var proxyServer = http.createServer(function (clientReq, clientRes) {
|
||||||
|
// 解析客户端请求的 URL
|
||||||
|
var parsedUrl = new URL("http://localhost".concat(clientReq.url));
|
||||||
|
var requestPath = parsedUrl.pathname;
|
||||||
|
// 检查是否为需要mock的路由
|
||||||
|
if (isMockRoute(requestPath)) {
|
||||||
|
var mockFile = getMockFilePath(requestPath);
|
||||||
|
console.log("[MOCK] \u62E6\u622A\u8DEF\u7531: ".concat(requestPath, " -> \u4F7F\u7528\u6587\u4EF6: ").concat(mockFile));
|
||||||
|
try {
|
||||||
|
// 构建完整的文件路径
|
||||||
|
var mockFilePath = path.join(__dirname, mockFile);
|
||||||
|
// 检查文件是否存在
|
||||||
|
if (!fs.existsSync(mockFilePath)) {
|
||||||
|
console.error("[MOCK] Mock\u6587\u4EF6\u4E0D\u5B58\u5728: ".concat(mockFilePath));
|
||||||
|
clientRes.writeHead(404, { 'Content-Type': 'application/json' });
|
||||||
|
clientRes.end(JSON.stringify({
|
||||||
|
error: 'Mock file not found',
|
||||||
|
route: requestPath,
|
||||||
|
file: mockFile,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 读取本地mock文件
|
||||||
|
var mockData = fs.readFileSync(mockFilePath, 'utf-8');
|
||||||
|
// 设置响应头
|
||||||
|
var contentType = CONFIG.defaultContentType || 'application/json';
|
||||||
|
clientRes.writeHead(200, {
|
||||||
|
'Content-Type': contentType,
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
||||||
|
'Access-Control-Allow-Headers': 'Content-Type',
|
||||||
|
'X-Mock-Source': mockFile,
|
||||||
|
'X-Mock-Timestamp': new Date().toISOString()
|
||||||
|
});
|
||||||
|
// 返回mock数据
|
||||||
|
clientRes.end(mockData);
|
||||||
|
console.log("[MOCK] \u6210\u529F\u8FD4\u56DEmock\u6570\u636E: ".concat(mockFile));
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error("[MOCK] \u8BFB\u53D6mock\u6587\u4EF6\u5931\u8D25: ".concat(mockFile), error);
|
||||||
|
clientRes.writeHead(500, { 'Content-Type': 'application/json' });
|
||||||
|
clientRes.end(JSON.stringify({
|
||||||
|
error: 'Failed to read mock data',
|
||||||
|
route: requestPath,
|
||||||
|
file: mockFile,
|
||||||
|
message: error.message,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return; // 直接返回,不转发到目标服务器
|
||||||
|
}
|
||||||
|
// 如果不是mock路由,正常代理转发
|
||||||
|
console.log("[PROXY] \u8F6C\u53D1\u8BF7\u6C42: ".concat(requestPath));
|
||||||
|
// 目标服务器的选项
|
||||||
|
var options = {
|
||||||
|
hostname: CONFIG.targetHost,
|
||||||
|
port: 443, // HTTPS 默认端口
|
||||||
|
method: clientReq.method,
|
||||||
|
path: parsedUrl.pathname + parsedUrl.search,
|
||||||
|
headers: __assign(__assign({}, clientReq.headers), { host: CONFIG.targetHost })
|
||||||
|
};
|
||||||
|
// 创建到目标服务器的 HTTPS 请求
|
||||||
|
var proxyReq = https.request(options, function (proxyRes) {
|
||||||
|
// 将目标服务器的响应头复制到客户端响应
|
||||||
|
clientRes.writeHead(proxyRes.statusCode, proxyRes.headers);
|
||||||
|
// 将目标服务器的响应数据管道传输到客户端
|
||||||
|
proxyRes.pipe(clientRes);
|
||||||
|
});
|
||||||
|
// 错误处理
|
||||||
|
proxyReq.on('error', function (err) {
|
||||||
|
console.error('Proxy request error:', err);
|
||||||
|
clientRes.writeHead(500, { 'Content-Type': 'application/json' });
|
||||||
|
clientRes.end(JSON.stringify({
|
||||||
|
error: 'Proxy error',
|
||||||
|
message: err.message,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
// 将客户端请求体管道传输到代理请求
|
||||||
|
clientReq.pipe(proxyReq);
|
||||||
|
});
|
||||||
|
// 添加管理接口用于重新加载配置
|
||||||
|
proxyServer.on('request', function (req, res) {
|
||||||
|
var parsedUrl = new URL("http://localhost".concat(req.url));
|
||||||
|
var pathname = parsedUrl.pathname;
|
||||||
|
// 管理接口:重新加载配置
|
||||||
|
if (pathname === '/__reload-config' && req.method === 'POST') {
|
||||||
|
try {
|
||||||
|
var oldCount = Object.keys(MOCK_ROUTES).length;
|
||||||
|
loadConfig();
|
||||||
|
var newCount = Object.keys(MOCK_ROUTES).length;
|
||||||
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
success: true,
|
||||||
|
message: 'Configuration reloaded successfully',
|
||||||
|
routesCount: newCount,
|
||||||
|
routesChanged: newCount - oldCount
|
||||||
|
}));
|
||||||
|
console.log("[ADMIN] \u901A\u8FC7API\u91CD\u65B0\u52A0\u8F7D\u914D\u7F6E (\u8DEF\u7531\u6570: ".concat(oldCount, " -> ").concat(newCount, ")"));
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
res.writeHead(500, { 'Content-Type': 'application/json' });
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 管理接口:查看当前配置
|
||||||
|
if (pathname === '/__config' && req.method === 'GET') {
|
||||||
|
try {
|
||||||
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
routes: MOCK_ROUTES,
|
||||||
|
config: CONFIG,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
totalRoutes: Object.keys(MOCK_ROUTES).length
|
||||||
|
}, null, 2));
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
res.writeHead(500, { 'Content-Type': 'application/json' });
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 初始化:第一次加载配置
|
||||||
|
loadConfig();
|
||||||
|
// 如果配置了文件监视,则监听配置文件变化
|
||||||
|
if (CONFIG.reloadOnChange) {
|
||||||
|
fs.watchFile(CONFIG_FILE, function (curr, prev) {
|
||||||
|
console.log("[CONFIG] \u914D\u7F6E\u6587\u4EF6\u5DF2\u4FEE\u6539\uFF0C\u91CD\u65B0\u52A0\u8F7D...");
|
||||||
|
try {
|
||||||
|
var oldRoutesCount = Object.keys(MOCK_ROUTES).length;
|
||||||
|
loadConfig();
|
||||||
|
var newRoutesCount = Object.keys(MOCK_ROUTES).length;
|
||||||
|
console.log("[CONFIG] \u914D\u7F6E\u91CD\u8F7D\u5B8C\u6210 (\u8DEF\u7531\u6570: ".concat(oldRoutesCount, " -> ").concat(newRoutesCount, ")"));
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error("[CONFIG] \u91CD\u65B0\u52A0\u8F7D\u914D\u7F6E\u6587\u4EF6\u5931\u8D25:", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log("[CONFIG] \u5DF2\u542F\u7528\u914D\u7F6E\u6587\u4EF6\u76D1\u89C6: ".concat(CONFIG_FILE));
|
||||||
|
}
|
||||||
|
proxyServer.listen(CONFIG.proxyPort, "0.0.0.0", function () {
|
||||||
|
console.log("========================================");
|
||||||
|
console.log("\u4EE3\u7406\u670D\u52A1\u5668\u8FD0\u884C\u5728: http://localhost:".concat(CONFIG.proxyPort));
|
||||||
|
console.log("\u76EE\u6807\u670D\u52A1\u5668: https://".concat(CONFIG.targetHost));
|
||||||
|
console.log("\u914D\u7F6E\u6587\u4EF6: ".concat(CONFIG_FILE));
|
||||||
|
console.log("\u5DF2\u914D\u7F6EMock\u8DEF\u7531: ".concat(Object.keys(MOCK_ROUTES).length, " \u4E2A").concat(CONFIG.mockEnabled !== false ? '' : '(当前 mockEnabled=false,未生效)'));
|
||||||
|
console.log("========================================");
|
||||||
|
console.log("\u7BA1\u7406\u63A5\u53E3:");
|
||||||
|
console.log(" GET http://localhost:".concat(CONFIG.proxyPort, "/__config \u67E5\u770B\u5F53\u524D\u914D\u7F6E"));
|
||||||
|
console.log(" POST http://localhost:".concat(CONFIG.proxyPort, "/__reload-config \u91CD\u65B0\u52A0\u8F7D\u914D\u7F6E"));
|
||||||
|
console.log("========================================");
|
||||||
|
console.log("Mock\u8DEF\u7531\u5217\u8868:");
|
||||||
|
for (var _i = 0, _a = Object.entries(MOCK_ROUTES); _i < _a.length; _i++) {
|
||||||
|
var _b = _a[_i], route = _b[0], file = _b[1];
|
||||||
|
var filePath = path.join(__dirname, file);
|
||||||
|
var exists = fs.existsSync(filePath) ? '✓' : '✗';
|
||||||
|
console.log(" ".concat(exists, " ").concat(route, " -> ").concat(file));
|
||||||
|
}
|
||||||
|
console.log("========================================");
|
||||||
|
});
|
||||||
@ -12,6 +12,8 @@ interface RouteConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface AppConfig {
|
interface AppConfig {
|
||||||
|
/** 为 false 时所有请求走代理,不命中 mock 路由;缺省为 true */
|
||||||
|
mockEnabled?: boolean;
|
||||||
cacheConfig: boolean;
|
cacheConfig: boolean;
|
||||||
reloadOnChange: boolean;
|
reloadOnChange: boolean;
|
||||||
defaultContentType: string;
|
defaultContentType: string;
|
||||||
@ -83,7 +85,7 @@ function loadConfig() {
|
|||||||
const configData: ConfigFile = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
|
const configData: ConfigFile = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
|
||||||
MOCK_ROUTES = filterActiveRoutes(configData.routes || {});
|
MOCK_ROUTES = filterActiveRoutes(configData.routes || {});
|
||||||
CONFIG = configData.config || CONFIG;
|
CONFIG = configData.config || CONFIG;
|
||||||
console.log(`[CONFIG] 配置文件已加载,共 ${Object.keys(MOCK_ROUTES).length} 个路由`);
|
console.log(`[CONFIG] 配置文件已加载,共 ${Object.keys(MOCK_ROUTES).length} 个路由${CONFIG.mockEnabled !== false ? '' : '(mock 已关闭,全部走代理)'}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证mock文件是否存在
|
// 验证mock文件是否存在
|
||||||
@ -127,6 +129,7 @@ function validateMockFiles() {
|
|||||||
|
|
||||||
// 检查是否为mock路由的函数
|
// 检查是否为mock路由的函数
|
||||||
function isMockRoute(requestPath: string): boolean {
|
function isMockRoute(requestPath: string): boolean {
|
||||||
|
if (CONFIG.mockEnabled === false) return false;
|
||||||
return MOCK_ROUTES.hasOwnProperty(requestPath);
|
return MOCK_ROUTES.hasOwnProperty(requestPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,7 +308,7 @@ proxyServer.listen(CONFIG.proxyPort, "0.0.0.0", () => {
|
|||||||
console.log(`代理服务器运行在: http://localhost:${CONFIG.proxyPort}`);
|
console.log(`代理服务器运行在: http://localhost:${CONFIG.proxyPort}`);
|
||||||
console.log(`目标服务器: https://${CONFIG.targetHost}`);
|
console.log(`目标服务器: https://${CONFIG.targetHost}`);
|
||||||
console.log(`配置文件: ${CONFIG_FILE}`);
|
console.log(`配置文件: ${CONFIG_FILE}`);
|
||||||
console.log(`已配置Mock路由: ${Object.keys(MOCK_ROUTES).length} 个`);
|
console.log(`已配置Mock路由: ${Object.keys(MOCK_ROUTES).length} 个${CONFIG.mockEnabled !== false ? '' : '(当前 mockEnabled=false,未生效)'}`);
|
||||||
console.log(`========================================`);
|
console.log(`========================================`);
|
||||||
console.log(`管理接口:`);
|
console.log(`管理接口:`);
|
||||||
console.log(` GET http://localhost:${CONFIG.proxyPort}/__config 查看当前配置`);
|
console.log(` GET http://localhost:${CONFIG.proxyPort}/__config 查看当前配置`);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user