@deppon/deppon-request 2.4.23 → 2.4.24
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/es/monitorBridge.d.ts +11 -0
- package/es/monitorBridge.js +181 -0
- package/es/request/resInterceptor.js +26 -1
- package/package.json +4 -4
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 识别 HTTP 200 下常见「业务失败」响应体(保守规则,减少误报)。
|
|
3
|
+
* @returns {{ message: string } | null}
|
|
4
|
+
*/
|
|
5
|
+
export function detectAxiosBusinessFailure(resData: any): {
|
|
6
|
+
message: string;
|
|
7
|
+
} | null;
|
|
8
|
+
/**
|
|
9
|
+
* @param {*} errorLike deppon 响应拦截器 reject 的 errorInfo,或 axios 错误对象
|
|
10
|
+
*/
|
|
11
|
+
export function reportDepponHttpErrorToMonitor(errorLike: any): void;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import './_virtual/_rollup-plugin-inject-process-env.js';
|
|
2
|
+
import _typeof from '@babel/runtime/helpers/typeof';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 当页面已通过 @deppon/deppon-monitor-browser 初始化 Monitor 时,
|
|
6
|
+
* 将 @deppon/deppon-request(axios)链路中的接口错误上报到同一套监控通道。
|
|
7
|
+
* 与 Monitor 在 window 上注册的桥接函数解耦,避免 deppon-request 依赖 monitor 包。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var HTTP_ERROR_TYPE = 'HTTP_ERROR';
|
|
11
|
+
function safeStringify(data, maxLen) {
|
|
12
|
+
var max = typeof maxLen === 'number' ? maxLen : 8000;
|
|
13
|
+
try {
|
|
14
|
+
var s = typeof data === 'string' ? data : JSON.stringify(data);
|
|
15
|
+
return s.length > max ? s.slice(0, max) + '...(truncated)' : s;
|
|
16
|
+
} catch (_e) {
|
|
17
|
+
return '';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function generateTraceId() {
|
|
21
|
+
try {
|
|
22
|
+
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
|
23
|
+
return crypto.randomUUID();
|
|
24
|
+
}
|
|
25
|
+
} catch (_e) {
|
|
26
|
+
/* noop */
|
|
27
|
+
}
|
|
28
|
+
return 'trace-' + Date.now() + '-' + Math.random().toString(36).slice(2, 11);
|
|
29
|
+
}
|
|
30
|
+
function pageHref() {
|
|
31
|
+
return typeof window !== 'undefined' && window.location ? window.location.href : '';
|
|
32
|
+
}
|
|
33
|
+
function shouldIgnoreRequestUrl(url) {
|
|
34
|
+
if (typeof window === 'undefined' || !url) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
var fn = window.__DEPPON_MONITOR_SHOULD_IGNORE_REQUEST_URL__;
|
|
38
|
+
if (typeof fn === 'function') {
|
|
39
|
+
try {
|
|
40
|
+
return fn(url) === true;
|
|
41
|
+
} catch (_e) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
function buildFullRequestUrl(req) {
|
|
48
|
+
if (!req) {
|
|
49
|
+
return '';
|
|
50
|
+
}
|
|
51
|
+
var raw = req.url || '';
|
|
52
|
+
if (raw.startsWith('http://') || raw.startsWith('https://')) {
|
|
53
|
+
return raw;
|
|
54
|
+
}
|
|
55
|
+
var base = req.baseURL || '';
|
|
56
|
+
if (!base) {
|
|
57
|
+
return raw;
|
|
58
|
+
}
|
|
59
|
+
return String(base).replace(/\/$/, '') + '/' + String(raw).replace(/^\//, '');
|
|
60
|
+
}
|
|
61
|
+
function buildPayloadFromDepponErrorInfo(errorLike) {
|
|
62
|
+
if (!errorLike || _typeof(errorLike) !== 'object') {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
var req = errorLike.request;
|
|
66
|
+
if (req && _typeof(req) === 'object' && typeof req.url === 'string') {
|
|
67
|
+
var url = buildFullRequestUrl(req);
|
|
68
|
+
return {
|
|
69
|
+
type: HTTP_ERROR_TYPE,
|
|
70
|
+
time: Date.now(),
|
|
71
|
+
name: 'HTTP Error',
|
|
72
|
+
message: errorLike.statusText || String(errorLike.status || '') || '请求失败',
|
|
73
|
+
url: pageHref(),
|
|
74
|
+
request: {
|
|
75
|
+
method: (req.method || 'GET').toString().toUpperCase(),
|
|
76
|
+
url: url || req.url,
|
|
77
|
+
data: req.data,
|
|
78
|
+
httpType: 'axios',
|
|
79
|
+
traceId: generateTraceId()
|
|
80
|
+
},
|
|
81
|
+
response: {
|
|
82
|
+
status: typeof errorLike.status === 'number' ? errorLike.status : 0,
|
|
83
|
+
data: safeStringify(errorLike.response !== undefined ? errorLike.response : '')
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
function buildPayloadFromAxiosError(errorLike) {
|
|
90
|
+
if (!errorLike || _typeof(errorLike) !== 'object') {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
var cfg = errorLike.config || {};
|
|
94
|
+
var url = buildFullRequestUrl(cfg);
|
|
95
|
+
var status = errorLike.response && typeof errorLike.response.status === 'number' ? errorLike.response.status : 0;
|
|
96
|
+
var resData = errorLike.response && errorLike.response.data;
|
|
97
|
+
var message = errorLike.message || errorLike.code || (status ? String(status) : '') || '网络异常';
|
|
98
|
+
return {
|
|
99
|
+
type: HTTP_ERROR_TYPE,
|
|
100
|
+
time: Date.now(),
|
|
101
|
+
name: 'HTTP Error',
|
|
102
|
+
message: message,
|
|
103
|
+
url: pageHref(),
|
|
104
|
+
request: {
|
|
105
|
+
method: (cfg.method || 'GET').toString().toUpperCase(),
|
|
106
|
+
url: url,
|
|
107
|
+
data: cfg.data,
|
|
108
|
+
httpType: 'axios',
|
|
109
|
+
traceId: generateTraceId()
|
|
110
|
+
},
|
|
111
|
+
response: {
|
|
112
|
+
status: status,
|
|
113
|
+
data: safeStringify(resData !== undefined ? resData : errorLike.message || '')
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 识别 HTTP 200 下常见「业务失败」响应体(保守规则,减少误报)。
|
|
120
|
+
* @returns {{ message: string } | null}
|
|
121
|
+
*/
|
|
122
|
+
function detectAxiosBusinessFailure(resData) {
|
|
123
|
+
if (resData == null || _typeof(resData) !== 'object') {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
if (resData.success === false) {
|
|
127
|
+
return {
|
|
128
|
+
message: String(resData.message || resData.msg || resData.error || 'success: false')
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (resData.result === false) {
|
|
132
|
+
return {
|
|
133
|
+
message: String(resData.message || resData.msg || resData.error || 'result: false')
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
var c = resData.code;
|
|
137
|
+
if (typeof c === 'number' && c !== 0 && c !== 200) {
|
|
138
|
+
return {
|
|
139
|
+
message: "".concat(String(resData.message || resData.msg || resData.error || '业务错误'), " (code=").concat(c, ")")
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (typeof c === 'string' && c.length > 0 && c !== '0' && c !== '200') {
|
|
143
|
+
if (/^[45][0-9]{2}$/.test(c)) {
|
|
144
|
+
return {
|
|
145
|
+
message: "".concat(String(resData.message || resData.msg || resData.error || '业务错误'), " (code=").concat(c, ")")
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @param {*} errorLike deppon 响应拦截器 reject 的 errorInfo,或 axios 错误对象
|
|
154
|
+
*/
|
|
155
|
+
function reportDepponHttpErrorToMonitor(errorLike) {
|
|
156
|
+
if (typeof window === 'undefined') {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
var report = window.__DEPPON_MONITOR_REPORT_HTTP_ERROR__;
|
|
160
|
+
if (typeof report !== 'function') {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
var payload = buildPayloadFromDepponErrorInfo(errorLike);
|
|
164
|
+
if (!payload) {
|
|
165
|
+
payload = buildPayloadFromAxiosError(errorLike);
|
|
166
|
+
}
|
|
167
|
+
if (!payload) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
var reqUrl = payload.request && payload.request.url;
|
|
171
|
+
if (shouldIgnoreRequestUrl(reqUrl)) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
report(payload);
|
|
176
|
+
} catch (_e) {
|
|
177
|
+
/* noop */
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export { detectAxiosBusinessFailure, reportDepponHttpErrorToMonitor };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '../_virtual/_rollup-plugin-inject-process-env.js';
|
|
2
2
|
import _typeof from '@babel/runtime/helpers/typeof';
|
|
3
|
+
import { detectAxiosBusinessFailure, reportDepponHttpErrorToMonitor } from '../monitorBridge.js';
|
|
3
4
|
|
|
4
5
|
function ResponseInterceptor(res, options) {
|
|
5
6
|
var resCode = res.status;
|
|
@@ -72,7 +73,8 @@ function ResponseInterceptor(res, options) {
|
|
|
72
73
|
response: res.data,
|
|
73
74
|
// 请求信息(从 config 中获取,包含完整的 headers,包括 cookie)
|
|
74
75
|
request: {
|
|
75
|
-
url: ((_res$config3 = res.config) === null || _res$config3 === void 0 ? void 0 : _res$config3.url) ||
|
|
76
|
+
url: ((_res$config3 = res.config) === null || _res$config3 === void 0 ? void 0 : _res$config3.url) || '',
|
|
77
|
+
baseURL: ((_res$config4 = res.config) === null || _res$config4 === void 0 ? void 0 : _res$config4.baseURL) || '',
|
|
76
78
|
method: ((_res$config5 = res.config) === null || _res$config5 === void 0 || (_res$config5 = _res$config5.method) === null || _res$config5 === void 0 ? void 0 : _res$config5.toUpperCase()) || 'GET',
|
|
77
79
|
params: ((_res$config6 = res.config) === null || _res$config6 === void 0 ? void 0 : _res$config6.params) || {},
|
|
78
80
|
data: ((_res$config7 = res.config) === null || _res$config7 === void 0 ? void 0 : _res$config7.data) || {},
|
|
@@ -81,9 +83,31 @@ function ResponseInterceptor(res, options) {
|
|
|
81
83
|
timeout: (_res$config8 = res.config) === null || _res$config8 === void 0 ? void 0 : _res$config8.timeout
|
|
82
84
|
}
|
|
83
85
|
};
|
|
86
|
+
reportDepponHttpErrorToMonitor(errorInfo);
|
|
84
87
|
return Promise.reject(errorInfo);
|
|
85
88
|
};
|
|
86
89
|
if (resSuccess) {
|
|
90
|
+
if (typeof window !== 'undefined' && window.__DEPPON_MONITOR_REPORT_AXIOS_BUSINESS__ === true) {
|
|
91
|
+
var biz = detectAxiosBusinessFailure(resData);
|
|
92
|
+
if (biz) {
|
|
93
|
+
var _res$config9, _res$config0, _res$config1, _res$config10, _res$config11, _res$config12;
|
|
94
|
+
var businessErrorInfo = {
|
|
95
|
+
status: res.status,
|
|
96
|
+
statusText: biz.message,
|
|
97
|
+
response: resData,
|
|
98
|
+
request: {
|
|
99
|
+
url: ((_res$config9 = res.config) === null || _res$config9 === void 0 ? void 0 : _res$config9.url) || '',
|
|
100
|
+
baseURL: ((_res$config0 = res.config) === null || _res$config0 === void 0 ? void 0 : _res$config0.baseURL) || '',
|
|
101
|
+
method: ((_res$config1 = res.config) === null || _res$config1 === void 0 || (_res$config1 = _res$config1.method) === null || _res$config1 === void 0 ? void 0 : _res$config1.toUpperCase()) || 'GET',
|
|
102
|
+
params: ((_res$config10 = res.config) === null || _res$config10 === void 0 ? void 0 : _res$config10.params) || {},
|
|
103
|
+
data: ((_res$config11 = res.config) === null || _res$config11 === void 0 ? void 0 : _res$config11.data) || {},
|
|
104
|
+
headers: {},
|
|
105
|
+
timeout: (_res$config12 = res.config) === null || _res$config12 === void 0 ? void 0 : _res$config12.timeout
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
reportDepponHttpErrorToMonitor(businessErrorInfo);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
87
111
|
// 如果没有 success 字段,直接返回数据(兼容没有 success 字段的接口)
|
|
88
112
|
return Promise.resolve(resData);
|
|
89
113
|
} else {
|
|
@@ -91,6 +115,7 @@ function ResponseInterceptor(res, options) {
|
|
|
91
115
|
}
|
|
92
116
|
}
|
|
93
117
|
function ResponseInterceptorError(res, options) {
|
|
118
|
+
reportDepponHttpErrorToMonitor(res);
|
|
94
119
|
return Promise.reject(res);
|
|
95
120
|
}
|
|
96
121
|
var res = ResponseInterceptor;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deppon/deppon-request",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.24",
|
|
4
4
|
"description": "Frontend HTTP request package",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@babel/runtime": "^7.17.7",
|
|
38
|
-
"@deppon/deppon-bridge": "2.4.
|
|
39
|
-
"@deppon/deppon-ui": "2.4.
|
|
40
|
-
"@deppon/deppon-utils": "2.4.
|
|
38
|
+
"@deppon/deppon-bridge": "2.4.24",
|
|
39
|
+
"@deppon/deppon-ui": "2.4.24",
|
|
40
|
+
"@deppon/deppon-utils": "2.4.24",
|
|
41
41
|
"axios": "^0.26.0",
|
|
42
42
|
"md5": "^2.3.0",
|
|
43
43
|
"qs": "^6.10.3"
|