whistle.mock-plugins 1.0.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.
Files changed (68) hide show
  1. package/API.md +247 -0
  2. package/README.md +91 -0
  3. package/app/cgi-bin/features.js +285 -0
  4. package/app/cgi-bin/index.js +31 -0
  5. package/app/cgi-bin/interfaces.js +409 -0
  6. package/app/cgi-bin/logs.js +151 -0
  7. package/app/cgi-bin/test-interface.js +152 -0
  8. package/app/public/index.html +1 -0
  9. package/app/public/js/index.js +2 -0
  10. package/app/public/js/index.js.LICENSE.txt +150 -0
  11. package/app/util/index.js +24 -0
  12. package/index.html +52 -0
  13. package/initialize.js +32 -0
  14. package/lib/dataManager.js +500 -0
  15. package/lib/index.js +3 -0
  16. package/lib/models.js +64 -0
  17. package/lib/routes/features.js +213 -0
  18. package/lib/routes/interfaces.js +304 -0
  19. package/lib/routes/proxy.js +239 -0
  20. package/lib/ruleManager.js +551 -0
  21. package/lib/rules-server.js +267 -0
  22. package/lib/server.js +805 -0
  23. package/lib/storage.js +16 -0
  24. package/lib/ui-server.js +68 -0
  25. package/package.json +51 -0
  26. package/public/bundle.js +2 -0
  27. package/public/bundle.js.LICENSE.txt +38 -0
  28. package/public/index.html +1 -0
  29. package/public/plugin.mock-plugin.html +14 -0
  30. package/rules.txt +22 -0
  31. package/test/rulesServer.test.js +120 -0
  32. package/ui/src/App.css +173 -0
  33. package/ui/src/App.js +24 -0
  34. package/ui/src/components/AppLayout.js +149 -0
  35. package/ui/src/components/FeatureCard.js +53 -0
  36. package/ui/src/components/Layout.js +94 -0
  37. package/ui/src/components/MainNav.js +42 -0
  38. package/ui/src/components/PageContainer.js +16 -0
  39. package/ui/src/index.html +11 -0
  40. package/ui/src/index.js +43 -0
  41. package/ui/src/pages/FileProxy.js +235 -0
  42. package/ui/src/pages/FilesPage.js +292 -0
  43. package/ui/src/pages/Home.js +128 -0
  44. package/ui/src/pages/HomePage.js +195 -0
  45. package/ui/src/pages/InterfaceManagement.js +829 -0
  46. package/ui/src/pages/InterfacePage.js +342 -0
  47. package/ui/src/pages/MockData.js +472 -0
  48. package/ui/src/pages/Settings.js +192 -0
  49. package/ui/src/pages/SettingsPage.js +165 -0
  50. package/ui/src/pages/UrlRedirect.js +225 -0
  51. package/ui/src/pages/Welcome.js +155 -0
  52. package/ui/src/services/api.js +186 -0
  53. package/ui/src/styles/app-layout.css +337 -0
  54. package/ui/src/styles/feature-card.css +172 -0
  55. package/ui/src/styles/file-proxy.css +301 -0
  56. package/ui/src/styles/global.css +224 -0
  57. package/ui/src/styles/home.css +123 -0
  58. package/ui/src/styles/index.css +419 -0
  59. package/ui/src/styles/interface-management.css +694 -0
  60. package/ui/src/styles/layout.css +159 -0
  61. package/ui/src/styles/logs-page.css +427 -0
  62. package/ui/src/styles/main-nav.css +52 -0
  63. package/ui/src/styles/mock-data.css +850 -0
  64. package/ui/src/styles/page-container.css +11 -0
  65. package/ui/src/styles/settings.css +208 -0
  66. package/ui/src/styles/url-redirect.css +279 -0
  67. package/ui/src/styles/welcome.css +282 -0
  68. package/webpack.config.js +49 -0
@@ -0,0 +1,409 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ module.exports = function(req, res) {
5
+ const dataDir = this.dataDir;
6
+ const interfacesFile = path.join(dataDir, 'interfaces.json');
7
+ const featuresFile = path.join(dataDir, 'features.json');
8
+
9
+ try {
10
+ // 确保配置文件存在并包含有效结构
11
+ if (!fs.existsSync(interfacesFile)) {
12
+ fs.writeJsonSync(interfacesFile, { interfaces: [] }, { spaces: 2 });
13
+ } else {
14
+ // 验证文件结构
15
+ try {
16
+ const fileData = fs.readJsonSync(interfacesFile);
17
+ if (!fileData || !fileData.interfaces) {
18
+ // 如果文件存在但结构无效,重新初始化
19
+ fs.writeJsonSync(interfacesFile, { interfaces: [] }, { spaces: 2 });
20
+ console.log('修复了损坏的interfaces文件结构');
21
+ }
22
+ } catch (e) {
23
+ // JSON解析错误时重新初始化文件
24
+ fs.writeJsonSync(interfacesFile, { interfaces: [] }, { spaces: 2 });
25
+ console.log('修复了无法解析的interfaces文件');
26
+ }
27
+ }
28
+
29
+ // 处理GET请求 - 获取接口列表
30
+ if (req.method === 'GET') {
31
+ const { featureId } = req.query;
32
+
33
+ if (!featureId) {
34
+ return res.status(400).json({
35
+ code: 400,
36
+ message: '功能ID不能为空',
37
+ data: null
38
+ });
39
+ }
40
+
41
+ // 检查功能是否存在
42
+ let featureExists = false;
43
+ if (fs.existsSync(featuresFile)) {
44
+ try {
45
+ const featuresData = fs.readJsonSync(featuresFile);
46
+ if (featuresData && featuresData.features) {
47
+ const feature = featuresData.features.find(item => item.id === featureId);
48
+ featureExists = !!feature;
49
+ }
50
+
51
+ if (!featureExists) {
52
+ return res.status(404).json({
53
+ code: 404,
54
+ message: '功能模块不存在',
55
+ data: null
56
+ });
57
+ }
58
+ } catch (err) {
59
+ console.error('读取功能文件错误:', err);
60
+ // 出错时继续处理
61
+ }
62
+ }
63
+
64
+ // 读取接口数据
65
+ let interfacesData;
66
+ try {
67
+ interfacesData = fs.readJsonSync(interfacesFile);
68
+ if (!interfacesData || !interfacesData.interfaces) {
69
+ interfacesData = { interfaces: [] };
70
+ }
71
+ } catch (err) {
72
+ console.error('读取接口列表错误:', err);
73
+ interfacesData = { interfaces: [] };
74
+ }
75
+
76
+ const filteredInterfaces = interfacesData.interfaces.filter(item => item.featureId === featureId);
77
+
78
+ return res.json({
79
+ code: 0,
80
+ message: '成功',
81
+ data: filteredInterfaces
82
+ });
83
+ }
84
+
85
+ // 处理POST请求 - 添加或更新接口
86
+ if (req.method === 'POST') {
87
+ const interfaceData = req.body;
88
+
89
+ // 参数验证
90
+ if (!interfaceData.featureId) {
91
+ return res.status(400).json({
92
+ code: 400,
93
+ message: '功能ID不能为空',
94
+ data: null
95
+ });
96
+ }
97
+
98
+ if (!interfaceData.name) {
99
+ return res.status(400).json({
100
+ code: 400,
101
+ message: '接口名称不能为空',
102
+ data: null
103
+ });
104
+ }
105
+
106
+ if (!interfaceData.urlPattern) {
107
+ return res.status(400).json({
108
+ code: 400,
109
+ message: 'URL匹配规则不能为空',
110
+ data: null
111
+ });
112
+ }
113
+
114
+ // 检查是否响应内容过大,超过100MB时给予特殊处理
115
+ if (interfaceData.responseContent && Buffer.byteLength(interfaceData.responseContent, 'utf8') > 100 * 1024 * 1024) {
116
+ return res.status(413).json({
117
+ code: 413,
118
+ message: '响应内容过大,超过100MB限制',
119
+ data: null
120
+ });
121
+ }
122
+
123
+ // 检查功能是否存在
124
+ let featureExists = false;
125
+ if (fs.existsSync(featuresFile)) {
126
+ try {
127
+ const featuresData = fs.readJsonSync(featuresFile);
128
+ if (featuresData && featuresData.features) {
129
+ const feature = featuresData.features.find(item => item.id === interfaceData.featureId);
130
+ featureExists = !!feature;
131
+ }
132
+
133
+ if (!featureExists) {
134
+ return res.status(404).json({
135
+ code: 404,
136
+ message: '功能模块不存在',
137
+ data: null
138
+ });
139
+ }
140
+ } catch (err) {
141
+ console.error('读取功能文件错误:', err);
142
+ // 忽略错误继续处理
143
+ }
144
+ }
145
+
146
+ // 读取接口数据
147
+ let interfacesData;
148
+ try {
149
+ interfacesData = fs.readJsonSync(interfacesFile);
150
+ if (!interfacesData || !interfacesData.interfaces) {
151
+ interfacesData = { interfaces: [] };
152
+ }
153
+ } catch (err) {
154
+ console.error('读取接口列表错误:', err);
155
+ interfacesData = { interfaces: [] };
156
+ }
157
+
158
+ // 如果有ID则更新,否则创建新接口
159
+ if (interfaceData.id) {
160
+ // 更新现有接口
161
+ const index = interfacesData.interfaces.findIndex(item => item.id === interfaceData.id);
162
+
163
+ if (index === -1) {
164
+ return res.status(404).json({
165
+ code: 404,
166
+ message: '接口不存在',
167
+ data: null
168
+ });
169
+ }
170
+
171
+ // 更新接口
172
+ interfacesData.interfaces[index] = {
173
+ ...interfacesData.interfaces[index],
174
+ name: interfaceData.name,
175
+ urlPattern: interfaceData.urlPattern,
176
+ proxyType: interfaceData.proxyType,
177
+ responseContent: interfaceData.responseContent,
178
+ targetUrl: interfaceData.targetUrl,
179
+ filePath: interfaceData.filePath,
180
+ httpStatus: interfaceData.httpStatus || 200,
181
+ responseDelay: interfaceData.responseDelay || 0,
182
+ httpMethod: interfaceData.httpMethod || 'ALL',
183
+ active: interfaceData.active !== false
184
+ };
185
+
186
+ fs.writeJsonSync(interfacesFile, interfacesData, { spaces: 2 });
187
+
188
+ return res.json({
189
+ code: 0,
190
+ message: '接口更新成功',
191
+ data: interfacesData.interfaces[index]
192
+ });
193
+ } else {
194
+ // 创建新接口
195
+ const newInterface = {
196
+ id: Date.now().toString(),
197
+ featureId: interfaceData.featureId,
198
+ name: interfaceData.name,
199
+ urlPattern: interfaceData.urlPattern,
200
+ proxyType: interfaceData.proxyType || 'response',
201
+ responseContent: interfaceData.responseContent || '',
202
+ targetUrl: interfaceData.targetUrl || '',
203
+ filePath: interfaceData.filePath || '',
204
+ httpStatus: interfaceData.httpStatus || 200,
205
+ responseDelay: interfaceData.responseDelay || 0,
206
+ httpMethod: interfaceData.httpMethod || 'ALL',
207
+ active: interfaceData.active !== false,
208
+ contentType: interfaceData.contentType || 'text/plain'
209
+ };
210
+
211
+ // 确保interfaces数组存在
212
+ if (!Array.isArray(interfacesData.interfaces)) {
213
+ interfacesData.interfaces = [];
214
+ }
215
+
216
+ interfacesData.interfaces.push(newInterface);
217
+ fs.writeJsonSync(interfacesFile, interfacesData, { spaces: 2 });
218
+
219
+ return res.json({
220
+ code: 0,
221
+ message: '接口创建成功',
222
+ data: newInterface
223
+ });
224
+ }
225
+ }
226
+
227
+ // 处理DELETE请求 - 删除接口
228
+ if (req.method === 'DELETE') {
229
+ const { id } = req.query;
230
+
231
+ if (!id) {
232
+ return res.status(400).json({
233
+ code: 400,
234
+ message: '接口ID不能为空',
235
+ data: null
236
+ });
237
+ }
238
+
239
+ let interfacesData;
240
+ try {
241
+ interfacesData = fs.readJsonSync(interfacesFile);
242
+ if (!interfacesData || !interfacesData.interfaces) {
243
+ interfacesData = { interfaces: [] };
244
+ }
245
+ } catch (err) {
246
+ console.error('读取接口列表错误:', err);
247
+ interfacesData = { interfaces: [] };
248
+ }
249
+
250
+ const index = interfacesData.interfaces.findIndex(item => item.id === id);
251
+
252
+ if (index === -1) {
253
+ return res.status(404).json({
254
+ code: 404,
255
+ message: '接口不存在',
256
+ data: null
257
+ });
258
+ }
259
+
260
+ // 删除接口
261
+ const deletedInterface = interfacesData.interfaces.splice(index, 1)[0];
262
+ fs.writeJsonSync(interfacesFile, interfacesData, { spaces: 2 });
263
+
264
+ return res.json({
265
+ code: 0,
266
+ message: '接口删除成功',
267
+ data: deletedInterface
268
+ });
269
+ }
270
+
271
+ // 处理 PUT 请求 - 更新接口
272
+ if (req.method === 'PUT') {
273
+ const { id } = req.query;
274
+ const interfaceData = req.body;
275
+
276
+ if (!id) {
277
+ return res.status(400).json({
278
+ code: 400,
279
+ message: '接口ID不能为空',
280
+ data: null
281
+ });
282
+ }
283
+
284
+ // 读取接口数据
285
+ let interfacesData;
286
+ try {
287
+ interfacesData = fs.readJsonSync(interfacesFile);
288
+ if (!interfacesData || !interfacesData.interfaces) {
289
+ interfacesData = { interfaces: [] };
290
+ }
291
+ } catch (err) {
292
+ console.error('读取接口列表错误:', err);
293
+ return res.status(500).json({
294
+ code: 500,
295
+ message: '读取接口数据失败',
296
+ data: null
297
+ });
298
+ }
299
+
300
+ // 查找并更新接口
301
+ const index = interfacesData.interfaces.findIndex(item => item.id === id);
302
+
303
+ if (index === -1) {
304
+ return res.status(404).json({
305
+ code: 404,
306
+ message: '接口不存在',
307
+ data: null
308
+ });
309
+ }
310
+
311
+ // 更新接口数据
312
+ const updatedInterface = {
313
+ ...interfacesData.interfaces[index],
314
+ name: interfaceData.name || interfacesData.interfaces[index].name,
315
+ urlPattern: interfaceData.urlPattern || interfacesData.interfaces[index].urlPattern,
316
+ proxyType: interfaceData.proxyType || interfacesData.interfaces[index].proxyType,
317
+ responseContent: interfaceData.responseContent !== undefined ? interfaceData.responseContent : interfacesData.interfaces[index].responseContent,
318
+ targetUrl: interfaceData.targetUrl !== undefined ? interfaceData.targetUrl : interfacesData.interfaces[index].targetUrl,
319
+ filePath: interfaceData.filePath !== undefined ? interfaceData.filePath : interfacesData.interfaces[index].filePath,
320
+ httpStatus: interfaceData.httpStatus || interfacesData.interfaces[index].httpStatus,
321
+ responseDelay: interfaceData.responseDelay !== undefined ? interfaceData.responseDelay : interfacesData.interfaces[index].responseDelay,
322
+ httpMethod: interfaceData.httpMethod || interfacesData.interfaces[index].httpMethod,
323
+ active: interfaceData.active !== undefined ? interfaceData.active : interfacesData.interfaces[index].active,
324
+ contentType: interfaceData.contentType || interfacesData.interfaces[index].contentType,
325
+ updatedAt: new Date().toISOString()
326
+ };
327
+
328
+ interfacesData.interfaces[index] = updatedInterface;
329
+ fs.writeJsonSync(interfacesFile, interfacesData, { spaces: 2 });
330
+
331
+ return res.json({
332
+ code: 0,
333
+ message: '接口更新成功',
334
+ data: updatedInterface
335
+ });
336
+ }
337
+
338
+ // 处理 PATCH 请求 - 部分更新接口(如启用/禁用状态)
339
+ if (req.method === 'PATCH') {
340
+ const { id } = req.query;
341
+ const patchData = req.body;
342
+
343
+ if (!id) {
344
+ return res.status(400).json({
345
+ code: 400,
346
+ message: '接口ID不能为空',
347
+ data: null
348
+ });
349
+ }
350
+
351
+ // 读取接口数据
352
+ let interfacesData;
353
+ try {
354
+ interfacesData = fs.readJsonSync(interfacesFile);
355
+ if (!interfacesData || !interfacesData.interfaces) {
356
+ interfacesData = { interfaces: [] };
357
+ }
358
+ } catch (err) {
359
+ console.error('读取接口列表错误:', err);
360
+ return res.status(500).json({
361
+ code: 500,
362
+ message: '读取接口数据失败',
363
+ data: null
364
+ });
365
+ }
366
+
367
+ // 查找接口
368
+ const index = interfacesData.interfaces.findIndex(item => item.id === id);
369
+
370
+ if (index === -1) {
371
+ return res.status(404).json({
372
+ code: 404,
373
+ message: '接口不存在',
374
+ data: null
375
+ });
376
+ }
377
+
378
+ // 部分更新接口数据
379
+ const updatedInterface = {
380
+ ...interfacesData.interfaces[index],
381
+ ...patchData,
382
+ updatedAt: new Date().toISOString()
383
+ };
384
+
385
+ interfacesData.interfaces[index] = updatedInterface;
386
+ fs.writeJsonSync(interfacesFile, interfacesData, { spaces: 2 });
387
+
388
+ return res.json({
389
+ code: 0,
390
+ message: '接口更新成功',
391
+ data: updatedInterface
392
+ });
393
+ }
394
+
395
+ // 其他请求方法
396
+ return res.status(405).json({
397
+ code: 405,
398
+ message: '不支持的请求方法',
399
+ data: null
400
+ });
401
+ } catch (err) {
402
+ console.error('处理接口请求出错:', err);
403
+ return res.status(500).json({
404
+ code: 500,
405
+ message: '服务器内部错误: ' + err.message,
406
+ data: null
407
+ });
408
+ }
409
+ };
@@ -0,0 +1,151 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ module.exports = function(req, res) {
5
+ const dataDir = this.dataDir;
6
+ const logsFile = path.join(dataDir, 'logs.json');
7
+
8
+ // 处理GET请求 - 获取日志
9
+ if (req.method === 'GET') {
10
+ try {
11
+ // 解析查询参数
12
+ const limit = parseInt(req.query.limit) || 100;
13
+ const type = req.query.type || '';
14
+ const keyword = req.query.keyword || '';
15
+ const page = parseInt(req.query.page) || 1;
16
+ const pageSize = parseInt(req.query.pageSize) || 20;
17
+
18
+ // 确保日志文件存在
19
+ if (!fs.existsSync(logsFile)) {
20
+ fs.writeJsonSync(logsFile, { logs: [] }, { spaces: 2 });
21
+ return res.json({
22
+ code: 0,
23
+ message: '成功',
24
+ data: {
25
+ logs: [],
26
+ total: 0,
27
+ page: 1,
28
+ pageSize: pageSize,
29
+ totalPages: 0
30
+ }
31
+ });
32
+ }
33
+
34
+ // 读取日志
35
+ const logsData = fs.readJsonSync(logsFile);
36
+
37
+ // 确保日志结构正确
38
+ if (!logsData || !logsData.logs || !Array.isArray(logsData.logs)) {
39
+ logsData.logs = [];
40
+ }
41
+
42
+ // 标准化日志格式,确保每个日志项都有正确的字段
43
+ let logs = logsData.logs.map(log => {
44
+ if (!log) return null;
45
+
46
+ // 标准化事件类型字段,确保兼容前端过滤
47
+ // 将type转换为eventType确保前端能够正确过滤
48
+ return {
49
+ id: log.id || Date.now().toString(),
50
+ timestamp: log.timestamp || new Date().toISOString(),
51
+ eventType: log.eventType || log.type || 'unknown',
52
+ type: log.type || log.eventType || 'unknown',
53
+ method: log.method || '',
54
+ url: log.url || '',
55
+ status: log.status || '',
56
+ message: log.message || '',
57
+ pattern: log.pattern || '',
58
+ ...log // 保留原有其他字段
59
+ };
60
+ }).filter(Boolean); // 过滤掉null
61
+
62
+ // 根据类型过滤
63
+ if (type && type !== 'all') {
64
+ try {
65
+ logs = logs.filter(log =>
66
+ log && (log.eventType === type || log.type === type)
67
+ );
68
+ } catch (err) {
69
+ console.error('按类型过滤日志失败:', err);
70
+ // 出错时不过滤
71
+ }
72
+ }
73
+
74
+ // 根据关键词过滤
75
+ if (keyword) {
76
+ try {
77
+ logs = logs.filter(log => {
78
+ if (!log) return false;
79
+
80
+ // 检查关键字段是否包含关键词
81
+ const url = (log.url || '').toLowerCase();
82
+ const pattern = (log.pattern || '').toLowerCase();
83
+ const message = (log.message || '').toLowerCase();
84
+ const lowercaseKeyword = keyword.toLowerCase();
85
+
86
+ return url.includes(lowercaseKeyword) ||
87
+ pattern.includes(lowercaseKeyword) ||
88
+ message.includes(lowercaseKeyword);
89
+ });
90
+ } catch (err) {
91
+ console.error('按关键词过滤日志失败:', err);
92
+ // 出错时不过滤
93
+ }
94
+ }
95
+
96
+ // 计算总记录数和总页数
97
+ const total = logs.length;
98
+ const totalPages = Math.ceil(total / pageSize);
99
+
100
+ // 分页
101
+ const startIndex = (page - 1) * pageSize;
102
+ const pagedLogs = logs.slice(startIndex, startIndex + pageSize);
103
+
104
+ return res.json({
105
+ code: 0,
106
+ message: '成功',
107
+ data: {
108
+ logs: pagedLogs,
109
+ total: total,
110
+ page: page,
111
+ pageSize: pageSize,
112
+ totalPages: totalPages
113
+ }
114
+ });
115
+ } catch (err) {
116
+ console.error('获取日志失败:', err);
117
+ return res.status(500).json({
118
+ code: 500,
119
+ message: '获取日志失败: ' + err.message,
120
+ data: null
121
+ });
122
+ }
123
+ }
124
+
125
+ // 处理DELETE请求 - 清空日志
126
+ if (req.method === 'DELETE') {
127
+ try {
128
+ fs.writeJsonSync(logsFile, { logs: [] }, { spaces: 2 });
129
+
130
+ return res.json({
131
+ code: 0,
132
+ message: '日志已清空',
133
+ data: null
134
+ });
135
+ } catch (err) {
136
+ console.error('清空日志失败:', err);
137
+ return res.status(500).json({
138
+ code: 500,
139
+ message: '清空日志失败: ' + err.message,
140
+ data: null
141
+ });
142
+ }
143
+ }
144
+
145
+ // 其他请求方法
146
+ return res.status(405).json({
147
+ code: 405,
148
+ message: '不支持的请求方法',
149
+ data: null
150
+ });
151
+ };
@@ -0,0 +1,152 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const Mock = require('mockjs');
4
+
5
+ module.exports = async function(req, res) {
6
+ const dataDir = this.dataDir;
7
+ const interfacesFile = path.join(dataDir, 'interfaces.json');
8
+ const featuresFile = path.join(dataDir, 'features.json');
9
+
10
+ try {
11
+ // 只处理 POST 请求
12
+ if (req.method === 'POST') {
13
+ const { url, interfaceId } = req.body;
14
+
15
+ // 参数验证
16
+ if (!url) {
17
+ return res.status(400).json({
18
+ code: 400,
19
+ message: '测试URL不能为空',
20
+ data: null
21
+ });
22
+ }
23
+
24
+ if (!interfaceId) {
25
+ return res.status(400).json({
26
+ code: 400,
27
+ message: '接口ID不能为空',
28
+ data: null
29
+ });
30
+ }
31
+
32
+ // 读取接口数据
33
+ let interfacesData;
34
+ try {
35
+ interfacesData = fs.readJsonSync(interfacesFile);
36
+ if (!interfacesData || !interfacesData.interfaces) {
37
+ return res.status(404).json({
38
+ code: 404,
39
+ message: '未找到接口数据',
40
+ data: null
41
+ });
42
+ }
43
+ } catch (err) {
44
+ return res.status(500).json({
45
+ code: 500,
46
+ message: '读取接口数据失败',
47
+ data: null
48
+ });
49
+ }
50
+
51
+ // 查找指定接口
52
+ const targetInterface = interfacesData.interfaces.find(item => item.id === interfaceId);
53
+
54
+ if (!targetInterface) {
55
+ return res.status(404).json({
56
+ code: 404,
57
+ message: '指定的接口不存在',
58
+ data: null
59
+ });
60
+ }
61
+
62
+ // 检查接口是否已禁用
63
+ if (targetInterface.active === false) {
64
+ return res.status(400).json({
65
+ code: 400,
66
+ message: '接口已禁用,无法测试',
67
+ data: null
68
+ });
69
+ }
70
+
71
+ // 检查功能模块是否已禁用
72
+ try {
73
+ const featuresData = fs.readJsonSync(featuresFile);
74
+
75
+ if (featuresData && featuresData.features) {
76
+ const featureItem = featuresData.features.find(item => item.id === targetInterface.featureId);
77
+
78
+ if (featureItem && featureItem.active === false) {
79
+ return res.status(400).json({
80
+ code: 400,
81
+ message: '所属功能模块已禁用,接口无法使用',
82
+ data: null
83
+ });
84
+ }
85
+ }
86
+ } catch (err) {
87
+ // 忽略读取错误,继续处理
88
+ }
89
+
90
+ const startTime = Date.now();
91
+
92
+ // 处理内容,支持 Mock.js 模板语法
93
+ let responseBody = targetInterface.responseContent;
94
+
95
+ try {
96
+ // 如果响应内容是JSON,则尝试应用Mock.js模板
97
+ if (targetInterface.contentType && targetInterface.contentType.includes('json')) {
98
+ // 尝试解析JSON
99
+ const jsonTemplate = JSON.parse(responseBody);
100
+ // 使用Mock.js生成随机数据
101
+ const mockData = Mock.mock(jsonTemplate);
102
+ // 将结果转换回字符串
103
+ responseBody = JSON.stringify(mockData);
104
+ }
105
+ } catch (err) {
106
+ // 如果Mock失败,使用原始内容
107
+ }
108
+
109
+ // 模拟接口处理延迟
110
+ const delay = targetInterface.responseDelay || 0;
111
+ if (delay > 0) {
112
+ await new Promise(resolve => setTimeout(resolve, delay));
113
+ }
114
+
115
+ const endTime = Date.now();
116
+ const duration = endTime - startTime;
117
+
118
+ // 模拟接口处理
119
+ const responseData = {
120
+ statusCode: targetInterface.httpStatus || 200,
121
+ contentType: targetInterface.contentType || 'application/json; charset=utf-8',
122
+ responseBody: responseBody,
123
+ mockInfo: {
124
+ matchedPattern: targetInterface.urlPattern,
125
+ requestMethod: targetInterface.httpMethod,
126
+ delay: delay,
127
+ duration: duration,
128
+ timestamp: new Date().toISOString()
129
+ }
130
+ };
131
+
132
+ return res.json({
133
+ code: 0,
134
+ message: '成功',
135
+ data: responseData
136
+ });
137
+ } else {
138
+ // 不支持的请求方法
139
+ return res.status(405).json({
140
+ code: 405,
141
+ message: '不支持的请求方法',
142
+ data: null
143
+ });
144
+ }
145
+ } catch (err) {
146
+ return res.status(500).json({
147
+ code: 500,
148
+ message: '服务器内部错误: ' + err.message,
149
+ data: null
150
+ });
151
+ }
152
+ };
@@ -0,0 +1 @@
1
+ <!doctype html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Whistle Mock 数据工厂</title><script defer="defer" src="/js/index.js"></script></head><body><div id="root"></div></body></html>