sobey-monitor-sdk 1.1.8 → 1.1.10
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/dist/index.cjs.js +128 -15
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +18 -0
- package/dist/index.esm.js +128 -15
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +128 -15
- package/dist/index.umd.js.map +1 -1
- package/dist/types/index.d.ts +18 -0
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -768,12 +768,93 @@ function installHttpErrorHandler() {
|
|
|
768
768
|
* 检查是否是 SDK 自身的请求
|
|
769
769
|
*/
|
|
770
770
|
function isSdkRequest(url) {
|
|
771
|
+
// 检查是否匹配常见的 SDK 上报路径
|
|
772
|
+
if (url.includes('/monitor/api/report') ||
|
|
773
|
+
url.includes('/monitor/api/beacon') ||
|
|
774
|
+
url.includes('/monitor/api/config')) {
|
|
775
|
+
return true;
|
|
776
|
+
}
|
|
777
|
+
// 配置已初始化时,检查 dsn
|
|
778
|
+
if (config.isInitialized()) {
|
|
779
|
+
const cfg = config.get();
|
|
780
|
+
if (cfg.dsn && url.includes(cfg.dsn)) {
|
|
781
|
+
return true;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
return false;
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* 获取嵌套对象的字段值
|
|
788
|
+
* @param obj 对象
|
|
789
|
+
* @param path 字段路径,如 "status" 或 "data.code"
|
|
790
|
+
*/
|
|
791
|
+
function getNestedValue(obj, path) {
|
|
792
|
+
if (!obj || typeof obj !== 'object')
|
|
793
|
+
return undefined;
|
|
794
|
+
const keys = path.split('.');
|
|
795
|
+
let value = obj;
|
|
796
|
+
for (const key of keys) {
|
|
797
|
+
if (value === null || value === undefined)
|
|
798
|
+
return undefined;
|
|
799
|
+
value = value[key];
|
|
800
|
+
}
|
|
801
|
+
return value;
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* 检查单条规则是否匹配
|
|
805
|
+
*/
|
|
806
|
+
function matchRule(data, rule) {
|
|
807
|
+
const value = getNestedValue(data, rule.field);
|
|
808
|
+
switch (rule.operator) {
|
|
809
|
+
case 'exists':
|
|
810
|
+
return value !== undefined && value !== null;
|
|
811
|
+
case 'eq':
|
|
812
|
+
return value === rule.value;
|
|
813
|
+
case 'ne':
|
|
814
|
+
return value !== rule.value;
|
|
815
|
+
case 'gt':
|
|
816
|
+
return typeof value === 'number' && typeof rule.value === 'number' && value > rule.value;
|
|
817
|
+
case 'gte':
|
|
818
|
+
return typeof value === 'number' && typeof rule.value === 'number' && value >= rule.value;
|
|
819
|
+
case 'lt':
|
|
820
|
+
return typeof value === 'number' && typeof rule.value === 'number' && value < rule.value;
|
|
821
|
+
case 'lte':
|
|
822
|
+
return typeof value === 'number' && typeof rule.value === 'number' && value <= rule.value;
|
|
823
|
+
default:
|
|
824
|
+
return false;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* 检测业务错误
|
|
829
|
+
* @param responseBody 响应体字符串
|
|
830
|
+
* @returns 是否为业务错误
|
|
831
|
+
*/
|
|
832
|
+
function detectBusinessError(responseBody) {
|
|
833
|
+
if (!responseBody)
|
|
834
|
+
return false;
|
|
771
835
|
if (!config.isInitialized())
|
|
772
836
|
return false;
|
|
773
837
|
const cfg = config.get();
|
|
774
|
-
|
|
838
|
+
const rules = cfg.error?.businessErrorRules;
|
|
839
|
+
if (!rules || rules.length === 0)
|
|
840
|
+
return false;
|
|
841
|
+
try {
|
|
842
|
+
const data = JSON.parse(responseBody);
|
|
843
|
+
// 任一规则匹配时返回 true
|
|
844
|
+
for (const rule of rules) {
|
|
845
|
+
if (matchRule(data, rule)) {
|
|
846
|
+
if (cfg.debug) {
|
|
847
|
+
console.log('[Monitor] Business error detected by rule:', rule, 'data:', data);
|
|
848
|
+
}
|
|
849
|
+
return true;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
775
852
|
return false;
|
|
776
|
-
|
|
853
|
+
}
|
|
854
|
+
catch {
|
|
855
|
+
// JSON 解析失败,不是业务错误
|
|
856
|
+
return false;
|
|
857
|
+
}
|
|
777
858
|
}
|
|
778
859
|
function interceptXHR() {
|
|
779
860
|
XMLHttpRequest.prototype.open = function (method, url, async = true, username, password) {
|
|
@@ -826,6 +907,8 @@ function interceptXHR() {
|
|
|
826
907
|
},
|
|
827
908
|
});
|
|
828
909
|
}
|
|
910
|
+
const responseBody = this.responseText?.substring(0, 1000);
|
|
911
|
+
// HTTP 错误或业务错误
|
|
829
912
|
if (status === 0 || status >= 400) {
|
|
830
913
|
reportHttpError({
|
|
831
914
|
method: monitorData.method,
|
|
@@ -833,9 +916,20 @@ function interceptXHR() {
|
|
|
833
916
|
status,
|
|
834
917
|
duration,
|
|
835
918
|
requestBody: monitorData.requestBody,
|
|
836
|
-
responseBody
|
|
919
|
+
responseBody,
|
|
837
920
|
});
|
|
838
921
|
}
|
|
922
|
+
else if (status >= 200 && status < 300 && detectBusinessError(responseBody)) {
|
|
923
|
+
// HTTP 200 但检测到业务错误
|
|
924
|
+
reportHttpError({
|
|
925
|
+
method: monitorData.method,
|
|
926
|
+
url: monitorData.url,
|
|
927
|
+
status,
|
|
928
|
+
duration,
|
|
929
|
+
requestBody: monitorData.requestBody,
|
|
930
|
+
responseBody,
|
|
931
|
+
}, true);
|
|
932
|
+
}
|
|
839
933
|
});
|
|
840
934
|
return originalXHRSend.call(this, body);
|
|
841
935
|
};
|
|
@@ -877,8 +971,10 @@ function interceptFetch() {
|
|
|
877
971
|
},
|
|
878
972
|
});
|
|
879
973
|
}
|
|
880
|
-
|
|
881
|
-
|
|
974
|
+
// 检查是否配置了业务错误规则
|
|
975
|
+
const hasBusinessRules = cfg?.error?.businessErrorRules && cfg.error.businessErrorRules.length > 0;
|
|
976
|
+
// 只有在请求失败或配置了业务规则时才读取响应体
|
|
977
|
+
if (!response.ok || hasBusinessRules) {
|
|
882
978
|
const cloned = response.clone();
|
|
883
979
|
let responseBody;
|
|
884
980
|
try {
|
|
@@ -886,14 +982,28 @@ function interceptFetch() {
|
|
|
886
982
|
responseBody = responseBody.substring(0, 1000);
|
|
887
983
|
}
|
|
888
984
|
catch { }
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
985
|
+
if (!response.ok) {
|
|
986
|
+
// HTTP 错误
|
|
987
|
+
reportHttpError({
|
|
988
|
+
method,
|
|
989
|
+
url,
|
|
990
|
+
status,
|
|
991
|
+
duration,
|
|
992
|
+
requestBody,
|
|
993
|
+
responseBody,
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
else if (hasBusinessRules && detectBusinessError(responseBody)) {
|
|
997
|
+
// HTTP 200 但检测到业务错误
|
|
998
|
+
reportHttpError({
|
|
999
|
+
method,
|
|
1000
|
+
url,
|
|
1001
|
+
status,
|
|
1002
|
+
duration,
|
|
1003
|
+
requestBody,
|
|
1004
|
+
responseBody,
|
|
1005
|
+
}, true);
|
|
1006
|
+
}
|
|
897
1007
|
}
|
|
898
1008
|
return response;
|
|
899
1009
|
}
|
|
@@ -930,10 +1040,13 @@ function interceptFetch() {
|
|
|
930
1040
|
/**
|
|
931
1041
|
* 上报 HTTP 错误
|
|
932
1042
|
*/
|
|
933
|
-
function reportHttpError(httpInfo) {
|
|
1043
|
+
function reportHttpError(httpInfo, isBusinessError = false) {
|
|
1044
|
+
const message = isBusinessError
|
|
1045
|
+
? `Business Error ${httpInfo.method} ${httpInfo.url}`
|
|
1046
|
+
: `HTTP ${httpInfo.status} ${httpInfo.method} ${httpInfo.url}`;
|
|
934
1047
|
const errorData = {
|
|
935
1048
|
type: 'http_error',
|
|
936
|
-
message
|
|
1049
|
+
message,
|
|
937
1050
|
httpInfo,
|
|
938
1051
|
};
|
|
939
1052
|
reporter.reportError(errorData);
|