sobey-monitor-sdk 1.1.18 → 1.1.19

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.umd.js CHANGED
@@ -429,7 +429,7 @@
429
429
  });
430
430
  }
431
431
 
432
- var version = "1.1.17";
432
+ var version = "1.1.19";
433
433
 
434
434
  /**
435
435
  * 数据上报管理
@@ -861,6 +861,27 @@
861
861
  console.log(`[Monitor] HTTP status ${status} shouldReport: ${shouldReport}, configured codes:`, httpErrorStatusCodes);
862
862
  return shouldReport;
863
863
  }
864
+ /**
865
+ * 根据错误类型判断是否应该上报网络类错误(status = 0)
866
+ * @param errorType 错误类型:'timeout' | 'abort' | 'network'
867
+ * @returns 是否应该上报
868
+ */
869
+ function shouldReportNetworkTypeError(errorType) {
870
+ if (!config.isInitialized()) {
871
+ return false;
872
+ }
873
+ const cfg = config.get();
874
+ const errorConfig = cfg.error;
875
+ switch (errorType) {
876
+ case 'timeout':
877
+ return errorConfig?.reportTimeoutError === true;
878
+ case 'abort':
879
+ return errorConfig?.reportAbortError === true;
880
+ case 'network':
881
+ default:
882
+ return errorConfig?.reportNetworkError === true;
883
+ }
884
+ }
864
885
  /**
865
886
  * 获取嵌套对象的字段值
866
887
  * @param obj 对象
@@ -979,7 +1000,20 @@
979
1000
  if (monitorData) {
980
1001
  monitorData.startTime = Date.now();
981
1002
  monitorData.requestBody = typeof body === 'string' ? body : undefined;
1003
+ monitorData.errorType = undefined; // 初始化错误类型
982
1004
  }
1005
+ // 监听超时事件
1006
+ this.addEventListener('timeout', function () {
1007
+ if (monitorData) {
1008
+ monitorData.errorType = 'timeout';
1009
+ }
1010
+ });
1011
+ // 监听取消事件
1012
+ this.addEventListener('abort', function () {
1013
+ if (monitorData) {
1014
+ monitorData.errorType = 'abort';
1015
+ }
1016
+ });
983
1017
  this.addEventListener('loadend', function () {
984
1018
  if (!monitorData)
985
1019
  return;
@@ -993,6 +1027,11 @@
993
1027
  // 其他异常情况(0-网络错误、4xx-客户端错误、5xx-服务端错误)根据配置控制
994
1028
  const isError = status === 0 || status < 200 || status >= 400;
995
1029
  const shouldRecord = isRedirect || recordMode === 'all' || (recordMode === 'error' && isError);
1030
+ // 确定错误类型
1031
+ let errorType;
1032
+ if (status === 0) {
1033
+ errorType = monitorData.errorType || 'network';
1034
+ }
996
1035
  if (shouldRecord) {
997
1036
  context.addBreadcrumb({
998
1037
  type: 'request',
@@ -1002,12 +1041,22 @@
1002
1041
  url: monitorData.url,
1003
1042
  status,
1004
1043
  duration,
1044
+ errorType,
1005
1045
  },
1006
1046
  });
1007
1047
  }
1008
1048
  const responseBody = this.responseText?.substring(0, 1000);
1009
- // HTTP 错误(根据配置的状态码列表过滤)
1010
- if (shouldReportHttpError(status)) {
1049
+ // HTTP 错误上报逻辑
1050
+ let shouldReport = false;
1051
+ if (status === 0) {
1052
+ // status=0 使用独立的网络错误配置
1053
+ shouldReport = shouldReportNetworkTypeError(errorType);
1054
+ }
1055
+ else {
1056
+ // 其他状态码使用 httpErrorStatusCodes 配置
1057
+ shouldReport = shouldReportHttpError(status);
1058
+ }
1059
+ if (shouldReport) {
1011
1060
  reportHttpError({
1012
1061
  method: monitorData.method,
1013
1062
  url: monitorData.url,
@@ -1015,6 +1064,7 @@
1015
1064
  duration,
1016
1065
  requestBody: monitorData.requestBody,
1017
1066
  responseBody,
1067
+ errorType,
1018
1068
  });
1019
1069
  }
1020
1070
  else if (status >= 200 && status < 300 && detectBusinessError(responseBody)) {
@@ -1107,6 +1157,22 @@
1107
1157
  }
1108
1158
  catch (error) {
1109
1159
  const duration = Date.now() - startTime;
1160
+ const err = error;
1161
+ // 判断错误类型
1162
+ // AbortError 表示请求被取消(可能是手动取消或超时)
1163
+ // 注意:fetch 的超时通常也是通过 AbortController 实现的,所以无法区分超时和手动取消
1164
+ // 这里将 AbortError 统一标记为 'abort',如果需要区分超时,建议使用 XHR 或检查 error.message
1165
+ let errorType = 'network';
1166
+ if (err.name === 'AbortError') {
1167
+ // 尝试通过错误消息区分超时和取消
1168
+ // 一些超时实现会在 message 中包含 'timeout'
1169
+ if (err.message?.toLowerCase().includes('timeout')) {
1170
+ errorType = 'timeout';
1171
+ }
1172
+ else {
1173
+ errorType = 'abort';
1174
+ }
1175
+ }
1110
1176
  // 网络错误时根据配置决定是否添加到面包屑
1111
1177
  const cfg = config.isInitialized() ? config.get() : null;
1112
1178
  const recordMode = cfg?.behavior?.recordRequestBreadcrumb || 'error';
@@ -1120,18 +1186,20 @@
1120
1186
  url,
1121
1187
  status: 0,
1122
1188
  duration,
1123
- error: error.message,
1189
+ error: err.message,
1190
+ errorType,
1124
1191
  },
1125
1192
  });
1126
1193
  }
1127
- // 网络错误也遵守 httpErrorStatusCodes 配置
1128
- if (shouldReportHttpError(0)) {
1194
+ // 网络错误使用独立的配置项判断是否上报
1195
+ if (shouldReportNetworkTypeError(errorType)) {
1129
1196
  reportHttpError({
1130
1197
  method,
1131
1198
  url,
1132
1199
  status: 0,
1133
1200
  duration,
1134
1201
  requestBody,
1202
+ errorType,
1135
1203
  });
1136
1204
  }
1137
1205
  throw error;
@@ -1142,9 +1210,23 @@
1142
1210
  * 上报 HTTP 错误
1143
1211
  */
1144
1212
  function reportHttpError(httpInfo, isBusinessError = false) {
1145
- const message = isBusinessError
1146
- ? `Business Error ${httpInfo.method} ${httpInfo.url}`
1147
- : `HTTP ${httpInfo.status} ${httpInfo.method} ${httpInfo.url}`;
1213
+ let message;
1214
+ if (isBusinessError) {
1215
+ message = `Business Error ${httpInfo.method} ${httpInfo.url}`;
1216
+ }
1217
+ else if (httpInfo.status === 0 && httpInfo.errorType) {
1218
+ // 对于 status 0,显示具体的错误类型
1219
+ const errorTypeLabels = {
1220
+ 'timeout': 'Timeout',
1221
+ 'abort': 'Aborted',
1222
+ 'network': 'Network Error',
1223
+ };
1224
+ const label = errorTypeLabels[httpInfo.errorType] || 'Network Error';
1225
+ message = `HTTP ${label} ${httpInfo.method} ${httpInfo.url}`;
1226
+ }
1227
+ else {
1228
+ message = `HTTP ${httpInfo.status} ${httpInfo.method} ${httpInfo.url}`;
1229
+ }
1148
1230
  const errorData = {
1149
1231
  type: isBusinessError ? 'business_error' : 'http_error',
1150
1232
  message,