mm_os 3.3.0 → 3.3.1
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/core/base/mqtt/index.js +1109 -1106
- package/core/base/web/index.js +245 -243
- package/core/com/event/README.md +4 -4
- package/core/com/event/com.json +3 -3
- package/core/com/event/config.tpl.json +18 -18
- package/core/com/event/drive.js +132 -132
- package/core/com/event/index.js +344 -344
- package/core/com/event/script.js +25 -25
- package/core/com/middleware/com.js +1 -0
- package/core/com/sql/drive.js +1 -1
- package/core/com/static/index.js +1 -1
- package/index.js +50 -31
- package/middleware/cors/index.js +119 -0
- package/middleware/cors/middleware.json +20 -0
- package/middleware/csrf/index.js +202 -0
- package/middleware/csrf/middleware.json +24 -0
- package/middleware/ip_firewall/index.js +476 -0
- package/middleware/ip_firewall/middleware.json +109 -0
- package/middleware/mqtt_base/middleware.json +2 -1
- package/middleware/security_audit/index.js +13 -19
- package/middleware/security_audit/middleware.json +3 -3
- package/middleware/waf/index.js +27 -32
- package/middleware/waf_ddos/index.js +2 -2
- package/middleware/waf_ddos/middleware.json +3 -3
- package/middleware/waf_xss/index.js +1 -1
- package/middleware/waf_xss/middleware.json +1 -1
- package/middleware/web_after/middleware.json +2 -1
- package/middleware/web_base/middleware.json +2 -1
- package/middleware/web_before/middleware.json +2 -1
- package/middleware/web_check/middleware.json +2 -1
- package/middleware/web_main/middleware.json +2 -1
- package/middleware/web_proxy/middleware.json +2 -1
- package/middleware/web_render/middleware.json +2 -1
- package/middleware/web_socket/middleware.json +2 -1
- package/middleware/web_static/middleware.json +2 -1
- package/package.json +13 -11
- package/middleware/performance/index.js +0 -151
- package/middleware/performance/middleware.json +0 -16
- package/middleware/security_headers/index.js +0 -487
- package/middleware/security_headers/middleware.json +0 -45
- package/middleware/waf_ip/index.js +0 -379
- package/middleware/waf_ip/middleware.json +0 -49
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "security_audit",
|
|
3
3
|
"title": "综合日志审计系统",
|
|
4
4
|
"type": "security",
|
|
5
|
-
"
|
|
5
|
+
"state": 1,
|
|
6
6
|
"sort": 20,
|
|
7
7
|
"description": "合并了轻量级HTTP请求日志和安全审计功能的综合日志审计系统",
|
|
8
8
|
"config": {
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"compress": true
|
|
18
18
|
},
|
|
19
19
|
"database": {
|
|
20
|
-
"type": "
|
|
21
|
-
"collection": "
|
|
20
|
+
"type": "mysql",
|
|
21
|
+
"collection": "sys_audit_log"
|
|
22
22
|
},
|
|
23
23
|
"events": {
|
|
24
24
|
"authentication": true,
|
package/middleware/waf/index.js
CHANGED
|
@@ -155,10 +155,21 @@ function getClientIP(req) {
|
|
|
155
155
|
* @returns {Boolean} 是否在白名单中
|
|
156
156
|
*/
|
|
157
157
|
function isInWhitelist(ip, config) {
|
|
158
|
-
//
|
|
158
|
+
// 优先使用全局IP管理器
|
|
159
|
+
try {
|
|
160
|
+
var { is_ip_in_whitelist } = require('../../tools/ip_manager/ip.manager.global.js');
|
|
161
|
+
if (is_ip_in_whitelist(ip)) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
} catch (error) {
|
|
165
|
+
// 如果全局IP管理器不可用,使用本地配置
|
|
166
|
+
$.log.warn('全局IP管理器不可用,使用本地WAF白名单配置');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// 使用本地配置作为备用
|
|
159
170
|
const whitelist = config && config.ip_whitelist && Array.isArray(config.ip_whitelist)
|
|
160
171
|
? config.ip_whitelist
|
|
161
|
-
: ['127.0.0.1', '::1', 'localhost'
|
|
172
|
+
: ['127.0.0.1', '::1', 'localhost'];
|
|
162
173
|
|
|
163
174
|
return whitelist.includes(ip);
|
|
164
175
|
}
|
|
@@ -188,12 +199,11 @@ module.exports = function(server, config) {
|
|
|
188
199
|
// 设置默认配置
|
|
189
200
|
const defaultConfig = {
|
|
190
201
|
log: true,
|
|
191
|
-
ip_whitelist: ['127.0.0.1', '::1', 'localhost'
|
|
202
|
+
ip_whitelist: ['127.0.0.1', '::1', 'localhost'],
|
|
192
203
|
path_whitelist: ['/static', '/favicon.ico', '/api', '/public', '/assets']
|
|
193
204
|
};
|
|
194
205
|
|
|
195
|
-
//
|
|
196
|
-
console.log('WAF MIDDLEWARE INITIALIZED');
|
|
206
|
+
// WAF中间件已初始化
|
|
197
207
|
|
|
198
208
|
// 获取全局配置中的middleware.waf配置
|
|
199
209
|
let wafConfig = defaultConfig;
|
|
@@ -207,13 +217,13 @@ module.exports = function(server, config) {
|
|
|
207
217
|
if (globalConfig.middleware && globalConfig.middleware.waf) {
|
|
208
218
|
// 安全地合并默认配置和全局配置
|
|
209
219
|
wafConfig = Object.assign({}, defaultConfig, globalConfig.middleware.waf);
|
|
210
|
-
|
|
220
|
+
// WAF使用config.json中的全局配置
|
|
211
221
|
} else {
|
|
212
|
-
|
|
222
|
+
// WAF使用默认配置(config.json中无middleware.waf配置)
|
|
213
223
|
}
|
|
214
224
|
}
|
|
215
225
|
} catch (error) {
|
|
216
|
-
|
|
226
|
+
// 全局WAF配置加载错误已通过日志系统记录
|
|
217
227
|
// 出错时使用默认配置
|
|
218
228
|
wafConfig = defaultConfig;
|
|
219
229
|
}
|
|
@@ -228,7 +238,7 @@ module.exports = function(server, config) {
|
|
|
228
238
|
|
|
229
239
|
// 合并传入的config和全局配置
|
|
230
240
|
const mergedConfig = { ...wafConfig, ...(config || {}) };
|
|
231
|
-
|
|
241
|
+
// 合并后的WAF配置已生效
|
|
232
242
|
|
|
233
243
|
/* WAF(web防火墙) */
|
|
234
244
|
server.use(async (ctx, next) => {
|
|
@@ -243,23 +253,18 @@ module.exports = function(server, config) {
|
|
|
243
253
|
// 获取请求路径
|
|
244
254
|
const path = ctx.path;
|
|
245
255
|
|
|
246
|
-
//
|
|
247
|
-
console.log('WAF PROCESSING REQUEST');
|
|
248
|
-
console.log('URL:', ctx.url);
|
|
249
|
-
console.log('Path:', path);
|
|
250
|
-
console.log('Method:', ctx.method);
|
|
251
|
-
console.log('IP:', ip);
|
|
256
|
+
// WAF正在处理请求
|
|
252
257
|
|
|
253
258
|
// 检查IP是否在白名单中,如果是则跳过所有检查
|
|
254
259
|
if (isInWhitelist(ip, mergedConfig)) {
|
|
255
|
-
|
|
260
|
+
// IP在白名单中,跳过安全检查
|
|
256
261
|
await next();
|
|
257
262
|
return;
|
|
258
263
|
}
|
|
259
264
|
|
|
260
265
|
// 检查路径是否在白名单中
|
|
261
266
|
if (isPathWhitelisted(path, mergedConfig)) {
|
|
262
|
-
|
|
267
|
+
// 路径在白名单中,跳过安全检查
|
|
263
268
|
await next();
|
|
264
269
|
return;
|
|
265
270
|
}
|
|
@@ -268,12 +273,9 @@ module.exports = function(server, config) {
|
|
|
268
273
|
var url = ctx.url;
|
|
269
274
|
|
|
270
275
|
// 1. 使用正则表达式检查基本攻击特征
|
|
271
|
-
console.log('Step 1: Basic attack pattern check');
|
|
272
276
|
var danger = waf_check(url);
|
|
273
|
-
console.log('WAF check result:', danger ? danger.toString() : 'safe');
|
|
274
277
|
if (danger) {
|
|
275
|
-
|
|
276
|
-
// 阻止攻击请求,返回403禁止访问
|
|
278
|
+
// 检测到攻击请求,已阻止
|
|
277
279
|
ctx.status = 403;
|
|
278
280
|
ctx.body = {
|
|
279
281
|
code: 403,
|
|
@@ -284,13 +286,11 @@ module.exports = function(server, config) {
|
|
|
284
286
|
}
|
|
285
287
|
|
|
286
288
|
// 2. 专门检查路径遍历攻击
|
|
287
|
-
console.log('Step 2: Path traversal check');
|
|
288
289
|
const hasTraversal = checkPathTraversal(path);
|
|
289
290
|
const isSafe = isSafePath(path);
|
|
290
|
-
console.log('Path traversal check results:', { path, hasTraversal, isSafe });
|
|
291
291
|
|
|
292
292
|
if (hasTraversal || !isSafe) {
|
|
293
|
-
|
|
293
|
+
// 检测到路径遍历攻击,已阻止
|
|
294
294
|
ctx.status = 403;
|
|
295
295
|
ctx.body = {
|
|
296
296
|
code: 403,
|
|
@@ -300,14 +300,12 @@ module.exports = function(server, config) {
|
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
// 3. 检查请求参数中的路径遍历
|
|
303
|
-
console.log('Step 3: Query parameter traversal check');
|
|
304
303
|
const queryParams = ctx.query;
|
|
305
304
|
for (const [key, value] of Object.entries(queryParams)) {
|
|
306
305
|
if (typeof value === 'string') {
|
|
307
306
|
const paramHasTraversal = checkPathTraversal(value);
|
|
308
|
-
console.log('Param check:', { key, value, paramHasTraversal });
|
|
309
307
|
if (paramHasTraversal) {
|
|
310
|
-
|
|
308
|
+
// 检测到请求参数中的路径遍历攻击,已阻止
|
|
311
309
|
ctx.status = 403;
|
|
312
310
|
ctx.body = {
|
|
313
311
|
code: 403,
|
|
@@ -319,13 +317,11 @@ module.exports = function(server, config) {
|
|
|
319
317
|
}
|
|
320
318
|
|
|
321
319
|
// 4. 如果是POST请求,检查请求体
|
|
322
|
-
console.log('Step 4: POST body traversal check');
|
|
323
320
|
if (ctx.method === 'POST' && ctx.request.body) {
|
|
324
321
|
const bodyContent = JSON.stringify(ctx.request.body);
|
|
325
322
|
const bodyHasTraversal = checkPathTraversal(bodyContent);
|
|
326
|
-
console.log('Body check results:', bodyHasTraversal);
|
|
327
323
|
if (bodyHasTraversal) {
|
|
328
|
-
|
|
324
|
+
// 检测到请求体中的路径遍历攻击,已阻止
|
|
329
325
|
ctx.status = 403;
|
|
330
326
|
ctx.body = {
|
|
331
327
|
code: 403,
|
|
@@ -335,11 +331,10 @@ module.exports = function(server, config) {
|
|
|
335
331
|
}
|
|
336
332
|
}
|
|
337
333
|
|
|
338
|
-
console.log('WAF: All checks passed, continuing request');
|
|
339
334
|
// 所有检查通过,继续处理请求
|
|
340
335
|
await next();
|
|
341
336
|
} catch (error) {
|
|
342
|
-
|
|
337
|
+
// WAF中间件错误已通过日志系统记录
|
|
343
338
|
// 出错时默认允许请求继续处理
|
|
344
339
|
await next();
|
|
345
340
|
}
|
|
@@ -24,7 +24,7 @@ class Middleware {
|
|
|
24
24
|
// 时间窗口(毫秒)
|
|
25
25
|
window_ms: 60000,
|
|
26
26
|
// 每个IP在时间窗口内的最大请求数
|
|
27
|
-
max_requests:
|
|
27
|
+
max_requests: 500,
|
|
28
28
|
// 是否启用
|
|
29
29
|
enable: true
|
|
30
30
|
},
|
|
@@ -33,7 +33,7 @@ class Middleware {
|
|
|
33
33
|
// 时间窗口(毫秒)
|
|
34
34
|
window_ms: 60000,
|
|
35
35
|
// 每个IP对每个路径在时间窗口内的最大请求数
|
|
36
|
-
max_requests:
|
|
36
|
+
max_requests: 250,
|
|
37
37
|
// 是否启用
|
|
38
38
|
enable: true
|
|
39
39
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "waf_ddos",
|
|
3
3
|
"title": "综合流量控制与DDOS攻击防护中间件",
|
|
4
4
|
"type": "web_before",
|
|
5
|
-
"
|
|
5
|
+
"state": 1,
|
|
6
6
|
"sort": 12,
|
|
7
7
|
"desc": "提供DDOS攻击防护和速率限制,包括IP限流、路径限流、连接控制和IP封禁功能",
|
|
8
8
|
"config": {
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
"storage": "memory",
|
|
11
11
|
"ip_rate_limit": {
|
|
12
12
|
"window_ms": 60000,
|
|
13
|
-
"max_requests":
|
|
13
|
+
"max_requests": 500,
|
|
14
14
|
"enable": true
|
|
15
15
|
},
|
|
16
16
|
"path_rate_limit": {
|
|
17
17
|
"window_ms": 60000,
|
|
18
|
-
"max_requests":
|
|
18
|
+
"max_requests": 250,
|
|
19
19
|
"enable": true
|
|
20
20
|
},
|
|
21
21
|
"connection_limit": {
|
|
@@ -241,7 +241,7 @@ class Middleware {
|
|
|
241
241
|
ctx.set('X-XSS-Protection', '1; mode=block');
|
|
242
242
|
|
|
243
243
|
// Content-Security-Policy 头
|
|
244
|
-
|
|
244
|
+
ctx.set('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;");
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mm_os",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.1",
|
|
4
4
|
"description": "这是超级美眉服务端框架,用于快速构建应用程序。",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -41,23 +41,25 @@
|
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"compressing": "^2.0.0",
|
|
44
|
-
"
|
|
45
|
-
"koa
|
|
44
|
+
"js-beautify": "^1.15.4",
|
|
45
|
+
"koa": "^3.1.1",
|
|
46
|
+
"koa-body": "^7.0.0",
|
|
46
47
|
"koa-compress": "^5.1.1",
|
|
47
48
|
"koa-send": "^5.0.1",
|
|
48
49
|
"koa-websocket": "^7.0.0",
|
|
49
50
|
"mm_check": "^1.5.0",
|
|
50
|
-
"mm_email": "^1.0.
|
|
51
|
+
"mm_email": "^1.0.5",
|
|
51
52
|
"mm_excel": "^1.2.2",
|
|
52
|
-
"mm_expand": "^1.8.
|
|
53
|
+
"mm_expand": "^1.8.8",
|
|
53
54
|
"mm_html": "^1.1.7",
|
|
55
|
+
"mm_https": "^1.6.3",
|
|
54
56
|
"mm_koa_proxy": "^1.0.1",
|
|
55
|
-
"mm_logs": "^1.
|
|
56
|
-
"mm_machine": "^2.0.
|
|
57
|
-
"mm_mongodb": "^1.
|
|
57
|
+
"mm_logs": "^1.5.3",
|
|
58
|
+
"mm_machine": "^2.0.5",
|
|
59
|
+
"mm_mongodb": "^1.5.0",
|
|
58
60
|
"mm_mqtt": "^1.0.7",
|
|
59
|
-
"mm_mysql": "^2.0
|
|
60
|
-
"mm_redis": "^
|
|
61
|
+
"mm_mysql": "^2.1.0",
|
|
62
|
+
"mm_redis": "^2.0.2",
|
|
61
63
|
"mm_ret": "^1.4.1",
|
|
62
64
|
"mm_session": "^1.5.0",
|
|
63
65
|
"mm_statics": "^1.5.1",
|
|
@@ -66,4 +68,4 @@
|
|
|
66
68
|
"mosca": "^2.8.3",
|
|
67
69
|
"mqtt": "^5.14.1"
|
|
68
70
|
}
|
|
69
|
-
}
|
|
71
|
+
}
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 请求性能监控中间件
|
|
3
|
-
* 记录请求响应时间,监控慢请求,提供性能数据收集
|
|
4
|
-
*/
|
|
5
|
-
module.exports = function(server, config) {
|
|
6
|
-
if (config.web && !config.web.performance) {
|
|
7
|
-
return server;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// 默认配置
|
|
11
|
-
const cg = Object.assign({
|
|
12
|
-
slowThreshold: 1000, // 慢请求阈值,单位毫秒
|
|
13
|
-
enableMetrics: true, // 是否启用性能指标收集
|
|
14
|
-
ignorePaths: [] // 忽略监控的路径
|
|
15
|
-
}, config);
|
|
16
|
-
|
|
17
|
-
// 性能监控数据收集器
|
|
18
|
-
const performanceData = {
|
|
19
|
-
counters: new Map(), // 请求计数器
|
|
20
|
-
responseTimes: new Map(), // 响应时间数据
|
|
21
|
-
slowRequests: [] // 慢请求记录
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// 全局性能监控对象
|
|
25
|
-
$.performanceMonitor = {
|
|
26
|
-
record: function(path, responseTime) {
|
|
27
|
-
if (!cg.enableMetrics) return;
|
|
28
|
-
|
|
29
|
-
// 更新请求计数
|
|
30
|
-
if (!performanceData.counters.has(path)) {
|
|
31
|
-
performanceData.counters.set(path, 1);
|
|
32
|
-
performanceData.responseTimes.set(path, {
|
|
33
|
-
sum: responseTime,
|
|
34
|
-
count: 1,
|
|
35
|
-
min: responseTime,
|
|
36
|
-
max: responseTime
|
|
37
|
-
});
|
|
38
|
-
} else {
|
|
39
|
-
performanceData.counters.set(path, performanceData.counters.get(path) + 1);
|
|
40
|
-
const stats = performanceData.responseTimes.get(path);
|
|
41
|
-
stats.sum += responseTime;
|
|
42
|
-
stats.count += 1;
|
|
43
|
-
stats.min = Math.min(stats.min, responseTime);
|
|
44
|
-
stats.max = Math.max(stats.max, responseTime);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// 记录慢请求
|
|
48
|
-
if (responseTime > cg.slowThreshold) {
|
|
49
|
-
performanceData.slowRequests.push({
|
|
50
|
-
path: path,
|
|
51
|
-
time: new Date(),
|
|
52
|
-
responseTime: responseTime
|
|
53
|
-
});
|
|
54
|
-
// 限制慢请求记录数量
|
|
55
|
-
if (performanceData.slowRequests.length > 1000) {
|
|
56
|
-
performanceData.slowRequests.shift();
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
getStats: function() {
|
|
62
|
-
const result = {};
|
|
63
|
-
performanceData.counters.forEach((count, path) => {
|
|
64
|
-
const times = performanceData.responseTimes.get(path);
|
|
65
|
-
result[path] = {
|
|
66
|
-
count: count,
|
|
67
|
-
avg: times.sum / times.count,
|
|
68
|
-
min: times.min,
|
|
69
|
-
max: times.max
|
|
70
|
-
};
|
|
71
|
-
});
|
|
72
|
-
return result;
|
|
73
|
-
},
|
|
74
|
-
|
|
75
|
-
getSlowRequests: function(limit = 100) {
|
|
76
|
-
return performanceData.slowRequests.slice(-limit);
|
|
77
|
-
},
|
|
78
|
-
|
|
79
|
-
reset: function() {
|
|
80
|
-
performanceData.counters.clear();
|
|
81
|
-
performanceData.responseTimes.clear();
|
|
82
|
-
performanceData.slowRequests = [];
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
// 性能监控中间件
|
|
87
|
-
server.use(async (ctx, next) => {
|
|
88
|
-
// 检查是否需要忽略此路径
|
|
89
|
-
const shouldIgnore = cg.ignorePaths.some(pattern => {
|
|
90
|
-
if (typeof pattern === 'string') {
|
|
91
|
-
return ctx.path === pattern;
|
|
92
|
-
} else if (pattern instanceof RegExp) {
|
|
93
|
-
return pattern.test(ctx.path);
|
|
94
|
-
}
|
|
95
|
-
return false;
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
if (shouldIgnore) {
|
|
99
|
-
await next();
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const start = Date.now();
|
|
104
|
-
const startTime = process.hrtime();
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
await next();
|
|
108
|
-
} finally {
|
|
109
|
-
const ms = Date.now() - start;
|
|
110
|
-
const [seconds, nanoseconds] = process.hrtime(startTime);
|
|
111
|
-
const executionTime = seconds * 1000 + nanoseconds / 1000000;
|
|
112
|
-
|
|
113
|
-
// 设置响应时间头
|
|
114
|
-
ctx.set('X-Response-Time', `${ms}ms`);
|
|
115
|
-
|
|
116
|
-
// 记录性能数据
|
|
117
|
-
$.performanceMonitor.record(ctx.path, ms);
|
|
118
|
-
|
|
119
|
-
// 慢请求报警
|
|
120
|
-
if (ms > cg.slowThreshold) {
|
|
121
|
-
const clientIP = ctx.headers['x-forwarded-for'] || ctx.ip;
|
|
122
|
-
$.log.warn(`【慢请求】 ${ctx.method} ${ctx.path} - ${ms}ms - ${clientIP}`);
|
|
123
|
-
|
|
124
|
-
// 如果是非常慢的请求(超过阈值的2倍),记录更多信息
|
|
125
|
-
if (ms > cg.slowThreshold * 2) {
|
|
126
|
-
const userAgent = ctx.headers['user-agent'] || 'unknown';
|
|
127
|
-
let requestData = '';
|
|
128
|
-
try {
|
|
129
|
-
if (ctx.method !== 'GET' && ctx.request.body) {
|
|
130
|
-
const bodyStr = JSON.stringify(ctx.request.body);
|
|
131
|
-
// 限制记录的请求体大小
|
|
132
|
-
requestData = bodyStr.length > 1024 ? bodyStr.substring(0, 1024) + '...' :
|
|
133
|
-
bodyStr;
|
|
134
|
-
}
|
|
135
|
-
} catch (e) {
|
|
136
|
-
requestData = '[无法序列化请求体]';
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
$.log.warn(
|
|
140
|
-
`【慢请求详情】路径: ${ctx.path}, 方法: ${ctx.method}, 耗时: ${ms}ms, IP: ${clientIP}, UA: ${userAgent.substring(0, 200)}`
|
|
141
|
-
);
|
|
142
|
-
if (requestData) {
|
|
143
|
-
$.log.warn(`【慢请求数据】${requestData}`);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
return server;
|
|
151
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "performance",
|
|
3
|
-
"title": "性能监控",
|
|
4
|
-
"description": "记录请求响应时间,监控慢请求,提供性能数据收集",
|
|
5
|
-
"mode": "web",
|
|
6
|
-
"priority": 10,
|
|
7
|
-
"config": {
|
|
8
|
-
"slowThreshold": 1000,
|
|
9
|
-
"enableMetrics": true,
|
|
10
|
-
"ignorePaths": [
|
|
11
|
-
"/favicon.ico",
|
|
12
|
-
"/robots.txt",
|
|
13
|
-
"/static/"
|
|
14
|
-
]
|
|
15
|
-
}
|
|
16
|
-
}
|