whistle.mock-plugins 1.0.6 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/cgi-bin/interfaces.js +35 -0
- package/app/cgi-bin/test-interface.js +260 -262
- package/app/public/js/index.js +1 -1
- package/app/public/js/index.js.LICENSE.txt +8 -2
- package/lib/models.js +12 -1
- package/lib/routes/interfaces.js +274 -56
- package/lib/ruleManager.js +41 -2
- package/lib/rules-server.js +246 -139
- package/package.json +1 -1
- package/ui/src/components/interface-management/InterfaceTestModal.js +313 -0
- package/ui/src/components/interface-management/PreviewModal.js +50 -0
- package/ui/src/components/interface-management/README.md +184 -0
- package/ui/src/components/interface-management/ResponseContentEditor.js +427 -0
- package/ui/src/components/interface-management/constants.js +36 -0
- package/ui/src/components/interface-management/index.js +6 -0
- package/ui/src/components/interface-management/utils.js +103 -0
- package/ui/src/pages/InterfaceManagement.js +360 -653
- package/ui/src/pages/MockData.js +32 -0
|
@@ -69,12 +69,16 @@
|
|
|
69
69
|
|
|
70
70
|
/** */
|
|
71
71
|
|
|
72
|
+
/** */
|
|
73
|
+
|
|
72
74
|
/** */
|
|
73
75
|
|
|
74
76
|
/** */
|
|
75
77
|
|
|
76
78
|
/** */
|
|
77
79
|
|
|
80
|
+
/** */
|
|
81
|
+
|
|
78
82
|
/** */
|
|
79
83
|
|
|
80
84
|
/** */
|
|
@@ -103,6 +107,8 @@
|
|
|
103
107
|
|
|
104
108
|
/** */
|
|
105
109
|
|
|
110
|
+
/** */
|
|
111
|
+
|
|
106
112
|
/** */
|
|
107
113
|
|
|
108
114
|
/** */
|
|
@@ -127,12 +133,12 @@
|
|
|
127
133
|
|
|
128
134
|
/** */
|
|
129
135
|
|
|
130
|
-
/** */
|
|
131
|
-
|
|
132
136
|
/** */
|
|
133
137
|
|
|
134
138
|
/** */
|
|
135
139
|
|
|
140
|
+
/** */
|
|
141
|
+
|
|
136
142
|
/** */
|
|
137
143
|
|
|
138
144
|
/** */
|
package/lib/models.js
CHANGED
|
@@ -15,6 +15,15 @@
|
|
|
15
15
|
* @property {string} updatedAt - 最后更新时间,ISO 字符串格式
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* 响应内容数据模型
|
|
20
|
+
* @typedef {Object} Response
|
|
21
|
+
* @property {string} id - 响应唯一标识符
|
|
22
|
+
* @property {string} name - 响应名称
|
|
23
|
+
* @property {string} description - 响应描述
|
|
24
|
+
* @property {string} content - 响应内容,使用 Mock.js 语法
|
|
25
|
+
*/
|
|
26
|
+
|
|
18
27
|
/**
|
|
19
28
|
* 接口数据模型
|
|
20
29
|
* @typedef {Object} Interface
|
|
@@ -23,7 +32,9 @@
|
|
|
23
32
|
* @property {string} name - 接口名称
|
|
24
33
|
* @property {string} urlPattern - URL 匹配规则,支持精确匹配、通配符和正则表达式
|
|
25
34
|
* @property {string} proxyType - 代理类型,可选值: 'response'(数据模板), 'redirect'(URL重定向), 'file'(文件代理)
|
|
26
|
-
* @property {string} responseContent - 响应内容,使用 Mock.js
|
|
35
|
+
* @property {string} responseContent - 响应内容,使用 Mock.js 语法(向后兼容)
|
|
36
|
+
* @property {Array<Response>} responses - 多个响应内容,可选择不同响应
|
|
37
|
+
* @property {string} activeResponseId - 当前激活的响应ID
|
|
27
38
|
* @property {string} targetUrl - 重定向目标 URL,仅在 proxyType='redirect' 时有效
|
|
28
39
|
* @property {string} filePath - 文件路径,仅在 proxyType='file' 时有效
|
|
29
40
|
* @property {number} httpStatus - HTTP 状态码
|
package/lib/routes/interfaces.js
CHANGED
|
@@ -15,6 +15,109 @@ const DATA_DIR = storage.DATA_DIR;
|
|
|
15
15
|
// 确保数据目录存在
|
|
16
16
|
fs.ensureDirSync(DATA_DIR);
|
|
17
17
|
|
|
18
|
+
// 处理接口数据,确保兼容多响应格式
|
|
19
|
+
const processInterfaceData = (data) => {
|
|
20
|
+
const result = { ...data };
|
|
21
|
+
|
|
22
|
+
// 调试日志
|
|
23
|
+
console.log('=== 开始处理接口数据 ===');
|
|
24
|
+
console.log('原始数据:', JSON.stringify({
|
|
25
|
+
name: result.name,
|
|
26
|
+
hasResponses: !!result.responses,
|
|
27
|
+
responsesType: typeof result.responses,
|
|
28
|
+
responsesLength: result.responses ? result.responses.length : 0,
|
|
29
|
+
responses: result.responses,
|
|
30
|
+
responseContent: !!result.responseContent,
|
|
31
|
+
activeResponseId: result.activeResponseId
|
|
32
|
+
}, null, 2));
|
|
33
|
+
|
|
34
|
+
// 处理 responses 数组
|
|
35
|
+
if (result.responses && Array.isArray(result.responses) && result.responses.length > 0) {
|
|
36
|
+
console.log('发现 responses 数组,直接处理多响应数据');
|
|
37
|
+
|
|
38
|
+
// 确保每个响应都有合法的 id, name 和 content
|
|
39
|
+
result.responses = result.responses.map((resp, index) => {
|
|
40
|
+
console.log(`处理响应 ${index}:`, resp);
|
|
41
|
+
|
|
42
|
+
if (!resp.id) {
|
|
43
|
+
resp.id = Math.random().toString(36).substring(2, 15);
|
|
44
|
+
console.log(`为响应 ${index} 添加 ID:`, resp.id);
|
|
45
|
+
}
|
|
46
|
+
if (!resp.name) {
|
|
47
|
+
resp.name = `响应 ${index + 1}`;
|
|
48
|
+
console.log(`为响应 ${index} 添加默认名称:`, resp.name);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const processedResp = {
|
|
52
|
+
id: resp.id,
|
|
53
|
+
name: resp.name,
|
|
54
|
+
description: resp.description || '',
|
|
55
|
+
content: resp.content || '{}'
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
console.log(`处理后的响应 ${index}:`, processedResp);
|
|
59
|
+
return processedResp;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
console.log('处理后的响应数组长度:', result.responses.length);
|
|
63
|
+
console.log('所有处理后的响应:', result.responses);
|
|
64
|
+
|
|
65
|
+
// 如果有响应但没有设置 activeResponseId,默认使用第一个
|
|
66
|
+
if (!result.activeResponseId) {
|
|
67
|
+
result.activeResponseId = result.responses[0].id;
|
|
68
|
+
console.log('设置默认激活响应:', result.activeResponseId);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 确保 responseContent 字段始终存在(向后兼容)
|
|
72
|
+
const activeResponse = result.activeResponseId
|
|
73
|
+
? result.responses.find(r => r.id === result.activeResponseId)
|
|
74
|
+
: result.responses[0];
|
|
75
|
+
|
|
76
|
+
if (activeResponse) {
|
|
77
|
+
result.responseContent = activeResponse.content;
|
|
78
|
+
console.log('设置 responseContent 为当前激活响应内容');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
} else if (result.responseContent) {
|
|
82
|
+
// 如果没有提供 responses 但有 responseContent,创建默认响应(向后兼容)
|
|
83
|
+
console.log('创建默认响应,因为没有 responses 数组但有 responseContent');
|
|
84
|
+
result.responses = [{
|
|
85
|
+
id: Math.random().toString(36).substring(2, 15),
|
|
86
|
+
name: '默认响应',
|
|
87
|
+
description: '',
|
|
88
|
+
content: result.responseContent
|
|
89
|
+
}];
|
|
90
|
+
result.activeResponseId = result.responses[0].id;
|
|
91
|
+
console.log('创建的默认响应:', result.responses[0]);
|
|
92
|
+
|
|
93
|
+
} else {
|
|
94
|
+
// 如果既没有 responses 也没有 responseContent,创建一个空的默认响应
|
|
95
|
+
console.log('创建空的默认响应');
|
|
96
|
+
result.responses = [{
|
|
97
|
+
id: Math.random().toString(36).substring(2, 15),
|
|
98
|
+
name: '默认响应',
|
|
99
|
+
description: '',
|
|
100
|
+
content: '{}'
|
|
101
|
+
}];
|
|
102
|
+
result.activeResponseId = result.responses[0].id;
|
|
103
|
+
result.responseContent = '{}';
|
|
104
|
+
console.log('创建的空默认响应:', result.responses[0]);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 最终日志
|
|
108
|
+
console.log('=== 处理后的最终接口数据 ===');
|
|
109
|
+
console.log('最终数据:', JSON.stringify({
|
|
110
|
+
name: result.name,
|
|
111
|
+
responsesLength: result.responses.length,
|
|
112
|
+
responses: result.responses,
|
|
113
|
+
activeResponseId: result.activeResponseId,
|
|
114
|
+
hasResponseContent: !!result.responseContent
|
|
115
|
+
}, null, 2));
|
|
116
|
+
console.log('=== 接口数据处理完成 ===\n');
|
|
117
|
+
|
|
118
|
+
return result;
|
|
119
|
+
};
|
|
120
|
+
|
|
18
121
|
// 初始化路由
|
|
19
122
|
const initRouter = () => {
|
|
20
123
|
const router = express.Router();
|
|
@@ -25,33 +128,69 @@ const initRouter = () => {
|
|
|
25
128
|
// 获取所有接口
|
|
26
129
|
router.get('/interfaces', (req, res) => {
|
|
27
130
|
try {
|
|
131
|
+
const { featureId } = req.query;
|
|
132
|
+
|
|
28
133
|
// 读取所有功能
|
|
29
134
|
const featuresFile = path.join(DATA_DIR, 'features.json');
|
|
30
135
|
if (!fs.existsSync(featuresFile)) {
|
|
31
|
-
return res.json([]);
|
|
136
|
+
return res.json({ code: 0, data: [] });
|
|
32
137
|
}
|
|
33
138
|
|
|
34
139
|
const features = fs.readJsonSync(featuresFile);
|
|
35
140
|
let allInterfaces = [];
|
|
36
141
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const interfacesFile = path.join(DATA_DIR, `interfaces-${
|
|
142
|
+
if (featureId) {
|
|
143
|
+
// 获取特定功能的接口
|
|
144
|
+
const interfacesFile = path.join(DATA_DIR, `interfaces-${featureId}.json`);
|
|
40
145
|
if (fs.existsSync(interfacesFile)) {
|
|
41
146
|
const interfaces = fs.readJsonSync(interfacesFile);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
147
|
+
console.log('=== 获取接口:从文件读取的原始数据 ===');
|
|
148
|
+
console.log(`文件路径: ${interfacesFile}`);
|
|
149
|
+
console.log('原始接口数据:', JSON.stringify(interfaces, null, 2));
|
|
150
|
+
|
|
151
|
+
const processedInterfaces = interfaces.map((item, index) => {
|
|
152
|
+
console.log(`=== 处理接口 ${index}: ${item.name} ===`);
|
|
153
|
+
console.log('处理前的接口数据:', JSON.stringify(item, null, 2));
|
|
154
|
+
|
|
155
|
+
// 确保每个接口都经过数据处理
|
|
156
|
+
const processed = processInterfaceData(item);
|
|
157
|
+
console.log('处理后的接口数据:', JSON.stringify(processed, null, 2));
|
|
158
|
+
|
|
159
|
+
const feature = features.find(f => f.id === featureId);
|
|
160
|
+
const result = {
|
|
161
|
+
...processed,
|
|
162
|
+
featureName: feature ? feature.name : '未知功能'
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
console.log('最终接口数据:', JSON.stringify(result, null, 2));
|
|
166
|
+
return result;
|
|
167
|
+
});
|
|
168
|
+
allInterfaces = processedInterfaces;
|
|
48
169
|
}
|
|
49
|
-
}
|
|
170
|
+
} else {
|
|
171
|
+
// 读取每个功能的接口
|
|
172
|
+
features.forEach(feature => {
|
|
173
|
+
const interfacesFile = path.join(DATA_DIR, `interfaces-${feature.id}.json`);
|
|
174
|
+
if (fs.existsSync(interfacesFile)) {
|
|
175
|
+
const interfaces = fs.readJsonSync(interfacesFile);
|
|
176
|
+
// 确保每个接口都经过数据处理
|
|
177
|
+
const processedInterfaces = interfaces.map(item => {
|
|
178
|
+
const processed = processInterfaceData(item);
|
|
179
|
+
return {
|
|
180
|
+
...processed,
|
|
181
|
+
featureName: feature.name
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
allInterfaces = allInterfaces.concat(processedInterfaces);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
50
188
|
|
|
51
|
-
|
|
189
|
+
console.log(`获取接口列表成功,共 ${allInterfaces.length} 个接口`);
|
|
190
|
+
res.json({ code: 0, data: allInterfaces });
|
|
52
191
|
} catch (err) {
|
|
53
192
|
console.error('获取接口列表失败:', err);
|
|
54
|
-
res.status(500).json({
|
|
193
|
+
res.status(500).json({ code: 1, message: '获取接口列表失败: ' + err.message });
|
|
55
194
|
}
|
|
56
195
|
});
|
|
57
196
|
|
|
@@ -61,7 +200,7 @@ const initRouter = () => {
|
|
|
61
200
|
// 读取所有功能
|
|
62
201
|
const featuresFile = path.join(DATA_DIR, 'features.json');
|
|
63
202
|
if (!fs.existsSync(featuresFile)) {
|
|
64
|
-
return res.status(404).json({
|
|
203
|
+
return res.status(404).json({ code: 1, message: '接口不存在' });
|
|
65
204
|
}
|
|
66
205
|
|
|
67
206
|
const features = fs.readJsonSync(featuresFile);
|
|
@@ -74,8 +213,10 @@ const initRouter = () => {
|
|
|
74
213
|
const interfaces = fs.readJsonSync(interfacesFile);
|
|
75
214
|
const found = interfaces.find(item => item.id === req.params.id);
|
|
76
215
|
if (found) {
|
|
216
|
+
// 确保数据经过处理
|
|
217
|
+
const processed = processInterfaceData(found);
|
|
77
218
|
foundInterface = {
|
|
78
|
-
...
|
|
219
|
+
...processed,
|
|
79
220
|
featureName: feature.name
|
|
80
221
|
};
|
|
81
222
|
break;
|
|
@@ -84,127 +225,204 @@ const initRouter = () => {
|
|
|
84
225
|
}
|
|
85
226
|
|
|
86
227
|
if (!foundInterface) {
|
|
87
|
-
return res.status(404).json({
|
|
228
|
+
return res.status(404).json({ code: 1, message: '接口不存在' });
|
|
88
229
|
}
|
|
89
230
|
|
|
90
|
-
|
|
231
|
+
console.log(`获取接口详情成功: ${foundInterface.name},响应数量: ${foundInterface.responses ? foundInterface.responses.length : 0}`);
|
|
232
|
+
res.json({ code: 0, data: foundInterface });
|
|
91
233
|
} catch (err) {
|
|
92
234
|
console.error('获取接口详情失败:', err);
|
|
93
|
-
res.status(500).json({
|
|
235
|
+
res.status(500).json({ code: 1, message: '获取接口详情失败: ' + err.message });
|
|
94
236
|
}
|
|
95
237
|
});
|
|
96
238
|
|
|
97
239
|
// 创建接口
|
|
98
240
|
router.post('/interfaces', (req, res) => {
|
|
99
241
|
try {
|
|
100
|
-
const
|
|
242
|
+
const interfaceData = req.body;
|
|
101
243
|
|
|
102
|
-
if (!featureId || !
|
|
103
|
-
return res.status(400).json({
|
|
244
|
+
if (!interfaceData.featureId || !interfaceData.urlPattern) {
|
|
245
|
+
return res.status(400).json({
|
|
246
|
+
code: 1,
|
|
247
|
+
message: '功能ID和URL匹配规则为必填项'
|
|
248
|
+
});
|
|
104
249
|
}
|
|
105
250
|
|
|
106
251
|
// 检查功能是否存在
|
|
107
252
|
const featuresFile = path.join(DATA_DIR, 'features.json');
|
|
108
253
|
if (!fs.existsSync(featuresFile)) {
|
|
109
|
-
return res.status(404).json({
|
|
254
|
+
return res.status(404).json({
|
|
255
|
+
code: 1,
|
|
256
|
+
message: '功能不存在'
|
|
257
|
+
});
|
|
110
258
|
}
|
|
111
259
|
|
|
112
260
|
const features = fs.readJsonSync(featuresFile);
|
|
113
|
-
const feature = features.find(f => f.id === featureId);
|
|
261
|
+
const feature = features.find(f => f.id === interfaceData.featureId);
|
|
114
262
|
if (!feature) {
|
|
115
|
-
return res.status(404).json({
|
|
263
|
+
return res.status(404).json({
|
|
264
|
+
code: 1,
|
|
265
|
+
message: '功能不存在'
|
|
266
|
+
});
|
|
116
267
|
}
|
|
117
268
|
|
|
118
269
|
// 读取接口列表
|
|
119
|
-
const interfacesFile = path.join(DATA_DIR, `interfaces-${featureId}.json`);
|
|
270
|
+
const interfacesFile = path.join(DATA_DIR, `interfaces-${interfaceData.featureId}.json`);
|
|
120
271
|
const interfaces = fs.existsSync(interfacesFile)
|
|
121
272
|
? fs.readJsonSync(interfacesFile)
|
|
122
273
|
: [];
|
|
123
274
|
|
|
275
|
+
// 处理接口数据,确保兼容多响应格式
|
|
276
|
+
console.log('=== 创建接口:开始处理数据 ===');
|
|
277
|
+
console.log('接收到的接口数据:', JSON.stringify(interfaceData, null, 2));
|
|
278
|
+
const processedData = processInterfaceData(interfaceData);
|
|
279
|
+
console.log('处理后的接口数据:', JSON.stringify(processedData, null, 2));
|
|
280
|
+
|
|
124
281
|
// 创建新接口
|
|
125
282
|
const newInterface = {
|
|
126
283
|
id: uuidv4(),
|
|
127
|
-
|
|
128
|
-
path: interfacePath,
|
|
129
|
-
method,
|
|
130
|
-
status: status || 200,
|
|
131
|
-
delay: delay || 0,
|
|
132
|
-
description: description || '',
|
|
133
|
-
headers: headers || { 'Content-Type': 'application/json' },
|
|
134
|
-
responseBody: responseBody || {},
|
|
284
|
+
...processedData,
|
|
135
285
|
createdAt: new Date().toISOString(),
|
|
136
286
|
updatedAt: new Date().toISOString()
|
|
137
287
|
};
|
|
138
288
|
|
|
289
|
+
console.log('=== 创建接口:准备保存的完整接口数据 ===');
|
|
290
|
+
console.log('完整的新接口数据:', JSON.stringify(newInterface, null, 2));
|
|
291
|
+
|
|
139
292
|
interfaces.push(newInterface);
|
|
140
293
|
|
|
141
294
|
// 保存接口列表
|
|
142
295
|
fs.writeJsonSync(interfacesFile, interfaces, { spaces: 2 });
|
|
296
|
+
console.log('接口数据已保存到文件:', interfacesFile);
|
|
297
|
+
|
|
298
|
+
// 验证保存后从文件读取的数据
|
|
299
|
+
const savedInterfaces = fs.readJsonSync(interfacesFile);
|
|
300
|
+
const savedInterface = savedInterfaces.find(item => item.id === newInterface.id);
|
|
301
|
+
console.log('=== 创建接口:验证保存后的数据 ===');
|
|
302
|
+
console.log('从文件读取的保存后数据:', JSON.stringify(savedInterface, null, 2));
|
|
143
303
|
|
|
144
|
-
|
|
304
|
+
// 更新功能模块的接口数量
|
|
305
|
+
const featureIndex = features.findIndex(f => f.id === interfaceData.featureId);
|
|
306
|
+
features[featureIndex].interfaceCount = interfaces.length;
|
|
307
|
+
features[featureIndex].updatedAt = new Date().toISOString();
|
|
308
|
+
fs.writeJsonSync(featuresFile, features, { spaces: 2 });
|
|
309
|
+
|
|
310
|
+
console.log('=== 创建接口:准备返回的数据 ===');
|
|
311
|
+
console.log('返回给前端的数据:', JSON.stringify(newInterface, null, 2));
|
|
312
|
+
|
|
313
|
+
res.json({
|
|
314
|
+
code: 0,
|
|
315
|
+
message: '接口创建成功',
|
|
316
|
+
data: newInterface
|
|
317
|
+
});
|
|
145
318
|
} catch (err) {
|
|
146
319
|
console.error('创建接口失败:', err);
|
|
147
|
-
res.status(500).json({
|
|
320
|
+
res.status(500).json({
|
|
321
|
+
code: 1,
|
|
322
|
+
message: '创建接口失败: ' + err.message
|
|
323
|
+
});
|
|
148
324
|
}
|
|
149
325
|
});
|
|
150
326
|
|
|
151
327
|
// 更新接口
|
|
152
|
-
router.put('/interfaces
|
|
328
|
+
router.put('/interfaces', (req, res) => {
|
|
153
329
|
try {
|
|
154
|
-
const {
|
|
330
|
+
const { id } = req.query;
|
|
331
|
+
const interfaceData = req.body;
|
|
332
|
+
|
|
333
|
+
if (!id) {
|
|
334
|
+
return res.status(400).json({
|
|
335
|
+
code: 1,
|
|
336
|
+
message: '接口ID为必填项'
|
|
337
|
+
});
|
|
338
|
+
}
|
|
155
339
|
|
|
156
|
-
if (!featureId) {
|
|
157
|
-
return res.status(400).json({
|
|
340
|
+
if (!interfaceData.featureId) {
|
|
341
|
+
return res.status(400).json({
|
|
342
|
+
code: 1,
|
|
343
|
+
message: '功能ID为必填项'
|
|
344
|
+
});
|
|
158
345
|
}
|
|
159
346
|
|
|
160
347
|
// 检查功能是否存在
|
|
161
348
|
const featuresFile = path.join(DATA_DIR, 'features.json');
|
|
162
349
|
if (!fs.existsSync(featuresFile)) {
|
|
163
|
-
return res.status(404).json({
|
|
350
|
+
return res.status(404).json({
|
|
351
|
+
code: 1,
|
|
352
|
+
message: '功能不存在'
|
|
353
|
+
});
|
|
164
354
|
}
|
|
165
355
|
|
|
166
356
|
const features = fs.readJsonSync(featuresFile);
|
|
167
|
-
const feature = features.find(f => f.id === featureId);
|
|
357
|
+
const feature = features.find(f => f.id === interfaceData.featureId);
|
|
168
358
|
if (!feature) {
|
|
169
|
-
return res.status(404).json({
|
|
359
|
+
return res.status(404).json({
|
|
360
|
+
code: 1,
|
|
361
|
+
message: '功能不存在'
|
|
362
|
+
});
|
|
170
363
|
}
|
|
171
364
|
|
|
172
365
|
// 读取接口列表
|
|
173
|
-
const interfacesFile = path.join(DATA_DIR, `interfaces-${featureId}.json`);
|
|
366
|
+
const interfacesFile = path.join(DATA_DIR, `interfaces-${interfaceData.featureId}.json`);
|
|
174
367
|
if (!fs.existsSync(interfacesFile)) {
|
|
175
|
-
return res.status(404).json({
|
|
368
|
+
return res.status(404).json({
|
|
369
|
+
code: 1,
|
|
370
|
+
message: '接口不存在'
|
|
371
|
+
});
|
|
176
372
|
}
|
|
177
373
|
|
|
178
374
|
const interfaces = fs.readJsonSync(interfacesFile);
|
|
179
|
-
const index = interfaces.findIndex(item => item.id ===
|
|
375
|
+
const index = interfaces.findIndex(item => item.id === id);
|
|
180
376
|
|
|
181
377
|
if (index === -1) {
|
|
182
|
-
return res.status(404).json({
|
|
378
|
+
return res.status(404).json({
|
|
379
|
+
code: 1,
|
|
380
|
+
message: '接口不存在'
|
|
381
|
+
});
|
|
183
382
|
}
|
|
184
383
|
|
|
384
|
+
// 处理接口数据,确保兼容多响应格式
|
|
385
|
+
console.log('=== 更新接口:开始处理数据 ===');
|
|
386
|
+
console.log('接收到的接口数据:', JSON.stringify(interfaceData, null, 2));
|
|
387
|
+
const processedData = processInterfaceData(interfaceData);
|
|
388
|
+
console.log('处理后的接口数据:', JSON.stringify(processedData, null, 2));
|
|
389
|
+
|
|
185
390
|
// 更新接口
|
|
186
391
|
const updatedInterface = {
|
|
187
392
|
...interfaces[index],
|
|
188
|
-
|
|
189
|
-
path: interfacePath !== undefined ? interfacePath : interfaces[index].path,
|
|
190
|
-
method: method !== undefined ? method : interfaces[index].method,
|
|
191
|
-
status: status !== undefined ? status : interfaces[index].status,
|
|
192
|
-
delay: delay !== undefined ? delay : interfaces[index].delay,
|
|
193
|
-
description: description !== undefined ? description : interfaces[index].description,
|
|
194
|
-
headers: headers !== undefined ? headers : interfaces[index].headers,
|
|
195
|
-
responseBody: responseBody !== undefined ? responseBody : interfaces[index].responseBody,
|
|
393
|
+
...processedData,
|
|
196
394
|
updatedAt: new Date().toISOString()
|
|
197
395
|
};
|
|
198
396
|
|
|
397
|
+
console.log('=== 更新接口:准备保存的完整接口数据 ===');
|
|
398
|
+
console.log('完整的更新接口数据:', JSON.stringify(updatedInterface, null, 2));
|
|
399
|
+
|
|
199
400
|
interfaces[index] = updatedInterface;
|
|
200
401
|
|
|
201
402
|
// 保存接口列表
|
|
202
403
|
fs.writeJsonSync(interfacesFile, interfaces, { spaces: 2 });
|
|
404
|
+
console.log('接口数据已保存到文件:', interfacesFile);
|
|
203
405
|
|
|
204
|
-
|
|
406
|
+
// 验证保存后从文件读取的数据
|
|
407
|
+
const savedInterfaces = fs.readJsonSync(interfacesFile);
|
|
408
|
+
const savedInterface = savedInterfaces.find(item => item.id === id);
|
|
409
|
+
console.log('=== 更新接口:验证保存后的数据 ===');
|
|
410
|
+
console.log('从文件读取的保存后数据:', JSON.stringify(savedInterface, null, 2));
|
|
411
|
+
|
|
412
|
+
console.log('=== 更新接口:准备返回的数据 ===');
|
|
413
|
+
console.log('返回给前端的数据:', JSON.stringify(updatedInterface, null, 2));
|
|
414
|
+
|
|
415
|
+
res.json({
|
|
416
|
+
code: 0,
|
|
417
|
+
message: '接口更新成功',
|
|
418
|
+
data: updatedInterface
|
|
419
|
+
});
|
|
205
420
|
} catch (err) {
|
|
206
421
|
console.error('更新接口失败:', err);
|
|
207
|
-
res.status(500).json({
|
|
422
|
+
res.status(500).json({
|
|
423
|
+
code: 1,
|
|
424
|
+
message: '更新接口失败: ' + err.message
|
|
425
|
+
});
|
|
208
426
|
}
|
|
209
427
|
});
|
|
210
428
|
|
package/lib/ruleManager.js
CHANGED
|
@@ -266,6 +266,11 @@ const ruleManager = {
|
|
|
266
266
|
result = await this.handleUrlRedirect(interfaceObj, req, res);
|
|
267
267
|
}
|
|
268
268
|
else if (proxyType === 'data_template' || proxyType === 'response') {
|
|
269
|
+
// 添加CORS支持 - 设置跨域相关的响应头
|
|
270
|
+
const origin = req.headers.origin || req.headers.host;
|
|
271
|
+
res.setHeader('Access-Control-Allow-Origin', origin || '*');
|
|
272
|
+
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
273
|
+
|
|
269
274
|
result = await this.handleDataTemplate(interfaceObj, req, res);
|
|
270
275
|
}
|
|
271
276
|
else if (proxyType === 'file_proxy' || proxyType === 'file') {
|
|
@@ -367,7 +372,29 @@ const ruleManager = {
|
|
|
367
372
|
async handleDataTemplate(interfaceObj, req, res) {
|
|
368
373
|
// 兼容不同的字段命名
|
|
369
374
|
const config = interfaceObj.config || interfaceObj;
|
|
370
|
-
|
|
375
|
+
|
|
376
|
+
// 支持多响应系统
|
|
377
|
+
let template = '';
|
|
378
|
+
|
|
379
|
+
// 检查是否有多响应配置
|
|
380
|
+
if (config.responses && Array.isArray(config.responses) && config.responses.length > 0) {
|
|
381
|
+
// 获取当前激活的响应
|
|
382
|
+
const activeResponseId = config.activeResponseId;
|
|
383
|
+
const activeResponse = activeResponseId
|
|
384
|
+
? config.responses.find(r => r.id === activeResponseId)
|
|
385
|
+
: config.responses[0];
|
|
386
|
+
|
|
387
|
+
if (activeResponse) {
|
|
388
|
+
this.log(`[规则处理器] 使用响应: ${activeResponse.name || '未命名'}`);
|
|
389
|
+
template = activeResponse.content;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// 如果没有找到响应内容,回退到传统字段
|
|
394
|
+
if (!template) {
|
|
395
|
+
template = config.responseContent || config.template || '{}';
|
|
396
|
+
this.log(`[规则处理器] 使用传统响应内容`);
|
|
397
|
+
}
|
|
371
398
|
|
|
372
399
|
if (!template) {
|
|
373
400
|
res.end(JSON.stringify({ error: 'No template specified' }));
|
|
@@ -385,8 +412,20 @@ const ruleManager = {
|
|
|
385
412
|
|
|
386
413
|
// 发送数据
|
|
387
414
|
res.end(JSON.stringify(mockData));
|
|
388
|
-
|
|
415
|
+
|
|
416
|
+
// 返回处理结果,包含响应信息
|
|
417
|
+
return {
|
|
418
|
+
mockData,
|
|
419
|
+
mockInfo: {
|
|
420
|
+
delay: parseInt(config.responseDelay || config.delay || 0, 10),
|
|
421
|
+
timestamp: new Date().toISOString(),
|
|
422
|
+
responseName: config.responses && config.activeResponseId
|
|
423
|
+
? (config.responses.find(r => r.id === config.activeResponseId)?.name || '未命名')
|
|
424
|
+
: '默认响应'
|
|
425
|
+
}
|
|
426
|
+
};
|
|
389
427
|
} catch (err) {
|
|
428
|
+
this.log(`[规则处理器] 模板解析错误: ${err.message}`);
|
|
390
429
|
res.end(JSON.stringify({ error: 'Template parsing error', message: err.message }));
|
|
391
430
|
return { error: 'Template parsing error', message: err.message };
|
|
392
431
|
}
|