nstarter-http-request 0.1.11 → 0.1.13

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 (72) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -2
  3. package/dist/cjs/adapter/axios.adapter.js +97 -2
  4. package/dist/cjs/adapter/axios.adapter.js.map +1 -1
  5. package/dist/cjs/adapter/base.js +20 -1
  6. package/dist/cjs/adapter/base.js.map +1 -1
  7. package/dist/cjs/adapter/undici.adapter.js +97 -77
  8. package/dist/cjs/adapter/undici.adapter.js.map +1 -1
  9. package/dist/cjs/client.js +99 -56
  10. package/dist/cjs/client.js.map +1 -1
  11. package/dist/cjs/config.js +1 -1
  12. package/dist/cjs/config.js.map +1 -1
  13. package/dist/cjs/const/config.const.js +8 -3
  14. package/dist/cjs/const/config.const.js.map +1 -1
  15. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  16. package/dist/cjs/types/errors.js +30 -2
  17. package/dist/cjs/types/errors.js.map +1 -1
  18. package/dist/cjs/utils/index.js +2 -1
  19. package/dist/cjs/utils/index.js.map +1 -1
  20. package/dist/cjs/utils/redirect.js +138 -0
  21. package/dist/cjs/utils/redirect.js.map +1 -0
  22. package/dist/esm/adapter/axios.adapter.js +99 -4
  23. package/dist/esm/adapter/axios.adapter.js.map +1 -1
  24. package/dist/esm/adapter/base.js +20 -1
  25. package/dist/esm/adapter/base.js.map +1 -1
  26. package/dist/esm/adapter/undici.adapter.js +98 -78
  27. package/dist/esm/adapter/undici.adapter.js.map +1 -1
  28. package/dist/esm/client.js +100 -57
  29. package/dist/esm/client.js.map +1 -1
  30. package/dist/esm/config.js +1 -1
  31. package/dist/esm/config.js.map +1 -1
  32. package/dist/esm/const/config.const.js +7 -2
  33. package/dist/esm/const/config.const.js.map +1 -1
  34. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  35. package/dist/esm/types/errors.js +28 -1
  36. package/dist/esm/types/errors.js.map +1 -1
  37. package/dist/esm/utils/index.js +1 -0
  38. package/dist/esm/utils/index.js.map +1 -1
  39. package/dist/esm/utils/redirect.js +133 -0
  40. package/dist/esm/utils/redirect.js.map +1 -0
  41. package/dist/types/adapter/axios.adapter.d.ts +22 -0
  42. package/dist/types/adapter/axios.adapter.d.ts.map +1 -1
  43. package/dist/types/adapter/base.d.ts +6 -0
  44. package/dist/types/adapter/base.d.ts.map +1 -1
  45. package/dist/types/adapter/undici.adapter.d.ts +24 -12
  46. package/dist/types/adapter/undici.adapter.d.ts.map +1 -1
  47. package/dist/types/client.d.ts +11 -0
  48. package/dist/types/client.d.ts.map +1 -1
  49. package/dist/types/const/config.const.d.ts +6 -0
  50. package/dist/types/const/config.const.d.ts.map +1 -1
  51. package/dist/types/types/config.d.ts +2 -2
  52. package/dist/types/types/config.d.ts.map +1 -1
  53. package/dist/types/types/errors.d.ts +26 -1
  54. package/dist/types/types/errors.d.ts.map +1 -1
  55. package/dist/types/types/request_response.d.ts +1 -1
  56. package/dist/types/types/request_response.d.ts.map +1 -1
  57. package/dist/types/utils/index.d.ts +1 -0
  58. package/dist/types/utils/index.d.ts.map +1 -1
  59. package/dist/types/utils/redirect.d.ts +26 -0
  60. package/dist/types/utils/redirect.d.ts.map +1 -0
  61. package/package.json +1 -1
  62. package/src/adapter/axios.adapter.ts +128 -4
  63. package/src/adapter/base.ts +22 -1
  64. package/src/adapter/undici.adapter.ts +112 -91
  65. package/src/client.ts +114 -63
  66. package/src/config.ts +1 -1
  67. package/src/const/config.const.ts +8 -2
  68. package/src/types/config.ts +2 -3
  69. package/src/types/errors.ts +39 -1
  70. package/src/types/request_response.ts +1 -2
  71. package/src/utils/index.ts +1 -0
  72. package/src/utils/redirect.ts +163 -0
@@ -36,7 +36,6 @@ export declare class UndiciAdapter extends BaseHttpAdapter {
36
36
  /**
37
37
  * 构建 Dispatcher(代理或 TLS 配置)
38
38
  * @param options 请求选项
39
- * @param timeout 请求总超时时间
40
39
  */
41
40
  private buildDispatcher;
42
41
  /**
@@ -63,6 +62,10 @@ export declare class UndiciAdapter extends BaseHttpAdapter {
63
62
  * 获取请求级超时时间。
64
63
  */
65
64
  private resolveTimeout;
65
+ /**
66
+ * 获取传给 undici 的阶段超时时间。0 用于内部禁用 undici 默认阶段超时。
67
+ */
68
+ private resolveUndiciTimeout;
66
69
  /**
67
70
  * 判断超时时间是否启用。
68
71
  */
@@ -74,28 +77,37 @@ export declare class UndiciAdapter extends BaseHttpAdapter {
74
77
  */
75
78
  private handleUndiciError;
76
79
  /**
77
- * 按 axios 默认行为处理非 2xx 状态码。
80
+ * 2xx 和 304 作为成功结果返回。undici 未跟跳的 3xx 交回调用方。
78
81
  */
79
82
  private ensureSuccessStatus;
80
83
  /**
81
- * 按 axios maxContentLength 行为限制非流式响应体大小。
84
+ * 解析 Content-Length 响应头。仅接受合法的非负整数,重复头/非法值视为未知。
85
+ */
86
+ private parseContentLength;
87
+ /**
88
+ * 丢弃未读完的响应体并终止下载。
89
+ * undici 的 BodyReadable.destroy() 不带错误时会以 RequestAbortedError 触发 error 事件,
90
+ * 没有监听器会变成未捕获异常,因此先挂空监听器。
82
91
  */
83
- private ensureResponseBodySize;
92
+ private discardBody;
84
93
  /**
85
- * 计算已读取响应体的字节大小。
94
+ * 带大小上限地读取非流式响应体。
95
+ *
96
+ * 1. Content-Length 预检:响应头已声明超限时,不读取响应体,直接销毁并拒绝。
97
+ * 2. 逐分块累计字节数,累计值超过上限(等于上限放行)立即销毁响应流并拒绝,后续数据不再下载;
98
+ * 该行为对齐 axios(Node http 适配器)的 maxContentLength。
86
99
  */
87
- private getBodySize;
100
+ private readBodyWithLimit;
101
+ /**
102
+ * 基于已读取(已受大小限制)的字节构造 Response,复用运行时的 blob/formData 解析逻辑。
103
+ */
104
+ private toFetchResponse;
88
105
  /**
89
106
  * 读取响应体
90
107
  * @param response Undici 响应对象
91
- * @param responseType 响应类型
108
+ * @param options 请求选项
92
109
  */
93
110
  private readResponseBody;
94
- /**
95
- * 按 axios 的默认兼容行为读取 JSON 响应。
96
- * 空响应体或非 JSON 文本不应让成功状态码请求因为解析失败变成异常。
97
- */
98
- private readJsonResponseBody;
99
111
  /**
100
112
  * 获取状态文本
101
113
  * @param statusCode 状态码
@@ -1 +1 @@
1
- {"version":3,"file":"undici.adapter.d.ts","sourceRoot":"","sources":["../../../src/adapter/undici.adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACR,kBAAkB,EAClB,YAAY,EAEf,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAOzC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAS1C;;GAEG;AACH,qBAAa,aAAc,SAAQ,eAAe;IAC9C,SAAgB,IAAI,wBAAkC;IAEtD;;OAEG;IACI,WAAW,IAAI,OAAO;IAI7B;;;OAGG;cACa,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IA0DrF;;;OAGG;IACH,OAAO,CAAC,cAAc;IAUtB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAgBnB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAa3B;;;;OAIG;IACH,OAAO,CAAC,eAAe;IA2BvB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IA4B9B;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;IAiB/B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAoB1B;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IA2BjC;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAmBzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAc3B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA0B9B;;OAEG;IACH,OAAO,CAAC,WAAW;IAsBnB;;;;OAIG;YACW,gBAAgB;IAsC9B;;;OAGG;YACW,oBAAoB;IAalC;;;OAGG;IACH,OAAO,CAAC,aAAa;CAGxB"}
1
+ {"version":3,"file":"undici.adapter.d.ts","sourceRoot":"","sources":["../../../src/adapter/undici.adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACR,kBAAkB,EAClB,YAAY,EACf,MAAM,UAAU,CAAC;AAKlB,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAOzC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAU1C;;GAEG;AACH,qBAAa,aAAc,SAAQ,eAAe;IAC9C,SAAgB,IAAI,wBAAkC;IAEtD;;OAEG;IACI,WAAW,IAAI,OAAO;IAI7B;;;OAGG;cACa,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IA4DrF;;;OAGG;IACH,OAAO,CAAC,cAAc;IAUtB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAgBnB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAa3B;;;OAGG;IACH,OAAO,CAAC,eAAe;IA4BvB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IA4B9B;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;IAiB/B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAoB1B;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IA4BjC;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAK5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAmBzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAkB3B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAQ1B;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAKnB;;;;;;OAMG;YACW,iBAAiB;IAgC/B;;OAEG;IACH,OAAO,CAAC,eAAe;IAOvB;;;;OAIG;YACW,gBAAgB;IA0C9B;;;OAGG;IACH,OAAO,CAAC,aAAa;CAGxB"}
@@ -47,6 +47,13 @@ export declare class NsHttpClient implements IHttpClient {
47
47
  * @returns 响应结果
48
48
  */
49
49
  request<T = any>(options: HttpRequestOptions): Promise<HttpResponse<T>>;
50
+ /**
51
+ *
52
+ * @param options 请求选项
53
+ * @param remainedRedirects 剩余可重定向次数
54
+ * @returns 响应结果
55
+ */
56
+ private safeRequest;
50
57
  /**
51
58
  * 便捷方法:GET 请求
52
59
  */
@@ -71,6 +78,10 @@ export declare class NsHttpClient implements IHttpClient {
71
78
  * 记录响应日志
72
79
  */
73
80
  private logResponse;
81
+ /**
82
+ * 销毁不再交给调用方的响应流
83
+ */
84
+ private discardResponseStream;
74
85
  /**
75
86
  * 判断响应数据是否为流对象(Node.js Readable)
76
87
  */
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,12 @@ export declare const DEFAULT_LOGGING_CONFIG: LoggingConfig;
16
16
  * 默认请求配置
17
17
  */
18
18
  export declare const DEFAULT_REQUEST_CONFIG: RequestConfig;
19
+ /**
20
+ * 响应体大小预检的线上长度容差比例。
21
+ * axios 的 onDownloadProgress.total 是压缩后的 Content-Length,而 maxContentLength 按解压后计数;
22
+ * 不可压缩数据经 gzip 等压缩后可能略大于解压大小,预检仅在超过上限该比例时提前中止。
23
+ */
24
+ export declare const MAX_RESPONSE_SIZE_TOLERANCE_RATIO = 0.01;
19
25
  /**
20
26
  * 默认 HTTP 客户端配置
21
27
  */
@@ -1 +1 @@
1
- {"version":3,"file":"config.const.d.ts","sourceRoot":"","sources":["../../../src/const/config.const.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,cAAc,EACjB,MAAM,UAAU,CAAC;AAIlB;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAAgB,CAAC;AAE/C;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,cASrC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,aAKpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,aAOpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,EAAE,gBAKxC,CAAC"}
1
+ {"version":3,"file":"config.const.d.ts","sourceRoot":"","sources":["../../../src/const/config.const.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,cAAc,EACjB,MAAM,UAAU,CAAC;AAIlB;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAAgB,CAAC;AAE/C;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,cASrC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,aAKpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,aAMpC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,OAAO,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,0BAA0B,EAAE,gBAKxC,CAAC"}
@@ -59,8 +59,8 @@ export interface LoggingConfig {
59
59
  * 请求配置
60
60
  */
61
61
  export interface RequestConfig {
62
- /** 超时时间(毫秒) */
63
- timeout: number;
62
+ /** 超时时间(毫秒);不配置表示不限制请求超时 */
63
+ timeout?: number;
64
64
  /** 重试次数 */
65
65
  retries: number;
66
66
  /** 重试延迟(毫秒) */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/types/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACR,OAAO,EACP,iBAAiB,EACjB,eAAe,EAClB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,IAAI,CAAC,EAAE;QACH,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAA;KACnB,CAAC;CACL;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,YAAY;IACZ,kBAAkB,EAAE,OAAO,CAAC;IAC5B,gBAAgB;IAChB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,iBAAiB;IACjB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,gBAAgB;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,qBAAqB;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB;IAClB,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,WAAW;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wBAAwB;IACxB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,YAAY;IACZ,cAAc,EAAE,OAAO,CAAC;IACxB,YAAY;IACZ,eAAe,EAAE,OAAO,CAAC;IACzB,oBAAoB;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc;IACd,MAAM,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,eAAe;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW;IACX,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,cAAc;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB;IAClB,mBAAmB,EAAE,MAAM,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,YAAY;IACZ,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW;IACX,QAAQ,EAAE,cAAc,CAAC;IACzB,WAAW;IACX,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW;IACX,OAAO,EAAE,aAAa,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACpC,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;CACpC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/types/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACR,OAAO,EACP,iBAAiB,EACjB,eAAe,EAClB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,IAAI,CAAC,EAAE;QACH,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAA;KACnB,CAAC;CACL;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,YAAY;IACZ,kBAAkB,EAAE,OAAO,CAAC;IAC5B,gBAAgB;IAChB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,iBAAiB;IACjB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,gBAAgB;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,qBAAqB;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB;IAClB,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,WAAW;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wBAAwB;IACxB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,YAAY;IACZ,cAAc,EAAE,OAAO,CAAC;IACxB,YAAY;IACZ,eAAe,EAAE,OAAO,CAAC;IACzB,oBAAoB;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc;IACd,MAAM,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,4BAA4B;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW;IACX,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,cAAc;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB;IAClB,mBAAmB,EAAE,MAAM,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,YAAY;IACZ,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW;IACX,QAAQ,EAAE,cAAc,CAAC;IACzB,WAAW;IACX,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW;IACX,OAAO,EAAE,aAAa,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACpC,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;CACpC"}
@@ -10,7 +10,32 @@ export declare class HttpError extends Error {
10
10
  readonly status?: number | undefined;
11
11
  readonly response?: HttpResponse | undefined;
12
12
  readonly request?: HttpRequestOptions | undefined;
13
- constructor(message: string, code: string, status?: number | undefined, response?: HttpResponse | undefined, request?: HttpRequestOptions | undefined);
13
+ readonly retriable: boolean;
14
+ /**
15
+ * @param message 错误信息
16
+ * @param code 错误码
17
+ * @param status HTTP 状态码
18
+ * @param response 响应(不应携带不再需要的大体积响应体)
19
+ * @param request 请求选项
20
+ * @param retriable 是否允许重试,默认 true;重试无法改变结果的确定性失败应传 false
21
+ */
22
+ constructor(message: string, code: string, status?: number | undefined, response?: HttpResponse | undefined, request?: HttpRequestOptions | undefined, retriable?: boolean);
23
+ }
24
+ /**
25
+ * 响应体超过 maxResponseBodySize 限制的错误。
26
+ *
27
+ * - 错误码与文案对齐 axios 的 maxContentLength(ERR_BAD_RESPONSE)。
28
+ * - 重试不会改变响应体大小,因此标记为不可重试,避免每次重试都重复下载。
29
+ * - 不携带 response:仅保留状态码,防止超限数据随错误对象存活(与 axios 抛出该错误时一致)。
30
+ */
31
+ export declare class ResponseTooLargeError extends HttpError {
32
+ readonly maxResponseBodySize: number;
33
+ /**
34
+ * @param maxResponseBodySize 响应体大小上限
35
+ * @param request 请求选项
36
+ * @param status 响应状态码(未知时不传)
37
+ */
38
+ constructor(maxResponseBodySize: number, request: HttpRequestOptions, status?: number);
14
39
  }
15
40
  /**
16
41
  * 安全验证错误
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/types/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE3E;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;aAGZ,IAAI,EAAE,MAAM;aACZ,MAAM,CAAC,EAAE,MAAM;aACf,QAAQ,CAAC,EAAE,YAAY;aACvB,OAAO,CAAC,EAAE,kBAAkB;gBAJ5C,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,QAAQ,CAAC,EAAE,YAAY,YAAA,EACvB,OAAO,CAAC,EAAE,kBAAkB,YAAA;CAMnD;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;aAGhB,IAAI,EAAE,MAAM;aACZ,GAAG,CAAC,EAAE,MAAM;gBAF5B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,MAAM,YAAA;CAMnC"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/types/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE3E;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;aAWZ,IAAI,EAAE,MAAM;aACZ,MAAM,CAAC,EAAE,MAAM;aACf,QAAQ,CAAC,EAAE,YAAY;aACvB,OAAO,CAAC,EAAE,kBAAkB;aAC5B,SAAS;IAd7B;;;;;;;OAOG;gBAEC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,QAAQ,CAAC,EAAE,YAAY,YAAA,EACvB,OAAO,CAAC,EAAE,kBAAkB,YAAA,EAC5B,SAAS,UAAO;CAMvC;AAED;;;;;;GAMG;AACH,qBAAa,qBAAsB,SAAQ,SAAS;aAO5B,mBAAmB,EAAE,MAAM;IAN/C;;;;OAIG;gBAEiB,mBAAmB,EAAE,MAAM,EAC3C,OAAO,EAAE,kBAAkB,EAC3B,MAAM,CAAC,EAAE,MAAM;CAWtB;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;aAGhB,IAAI,EAAE,MAAM;aACZ,GAAG,CAAC,EAAE,MAAM;gBAF5B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,MAAM,YAAA;CAMnC"}
@@ -23,7 +23,7 @@ export interface HttpRequestOptions {
23
23
  params?: Record<string, string | number | boolean>;
24
24
  /** 请求体 */
25
25
  body?: any;
26
- /** 请求超时(毫秒,覆盖全局配置) */
26
+ /** 请求超时(毫秒,覆盖全局配置);不配置表示不限制请求超时 */
27
27
  timeout?: number;
28
28
  /** 重试次数(覆盖全局配置) */
29
29
  retries?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"request_response.d.ts","sourceRoot":"","sources":["../../../src/types/request_response.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1F;;GAEG;AACH,MAAM,MAAM,YAAY,GAClB,aAAa,GACb,MAAM,GACN,UAAU,GACV,MAAM,GACN,MAAM,GACN,QAAQ,GACR,UAAU,CAAC;AAEjB;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B,cAAc;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,aAAa;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU;IACV,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IAC1C,eAAe;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACnD,UAAU;IACV,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,sBAAsB;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mBAAmB;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,WAAW;IACX,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,GAAG;IACjC,YAAY;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,aAAa;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU;IACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,UAAU;IACV,IAAI,EAAE,CAAC,CAAC;IACR,WAAW;IACX,MAAM,EAAE,kBAAkB,CAAC;CAC9B"}
1
+ {"version":3,"file":"request_response.d.ts","sourceRoot":"","sources":["../../../src/types/request_response.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1F;;GAEG;AACH,MAAM,MAAM,YAAY,GAClB,aAAa,GACb,MAAM,GACN,UAAU,GACV,MAAM,GACN,MAAM,GACN,QAAQ,GACR,UAAU,CAAC;AAEjB;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B,cAAc;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,aAAa;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU;IACV,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IAC1C,eAAe;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACnD,UAAU;IACV,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mBAAmB;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,WAAW;IACX,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,GAAG;IACjC,YAAY;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,aAAa;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU;IACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,UAAU;IACV,IAAI,EAAE,CAAC,CAAC;IACR,WAAW;IACX,MAAM,EAAE,kBAAkB,CAAC;CAC9B"}
@@ -1,6 +1,7 @@
1
1
  export * as IpRangeUtils from './ip.range';
2
2
  export * as CommonUtils from './common';
3
3
  export * as DomainUtils from './domain';
4
+ export * as RedirectUtils from './redirect';
4
5
  export * as TraceContextUtils from './trace.context';
5
6
  export { TraceContext } from './trace.context';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,WAAW,MAAM,UAAU,CAAC;AACxC,OAAO,KAAK,WAAW,MAAM,UAAU,CAAC;AACxC,OAAO,KAAK,iBAAiB,MAAM,iBAAiB,CAAC;AAGrD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,WAAW,MAAM,UAAU,CAAC;AACxC,OAAO,KAAK,WAAW,MAAM,UAAU,CAAC;AACxC,OAAO,KAAK,aAAa,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,iBAAiB,MAAM,iBAAiB,CAAC;AAGrD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { HttpRequestOptions, HttpResponse } from '../types';
2
+ import { EClientAdapter } from '../const';
3
+ /**
4
+ * 判断状态码是否需要跟跳。
5
+ * @param status HTTP 状态码
6
+ */
7
+ export declare function isRedirectStatus(status: number): boolean;
8
+ /**
9
+ * 根据响应里的 Location 构造下一跳请求。
10
+ * 没有 Location 时返回 undefined,调用方把当前 3xx 原样返回。
11
+ * axios:POST 的 301/302,以及非 GET/HEAD 的 303,改成 GET 并去掉 body 和 content-*。
12
+ * undici:只有非 HEAD 的 303 改成 GET 并去掉 body;303 仍去掉 content-*。
13
+ * 两边都去掉 host;跨域去掉 authorization、cookie、proxy-authorization。
14
+ * @param options 当前这一跳的请求
15
+ * @param response 当前这一跳的响应
16
+ * @param adapter 当前适配器
17
+ * @param configuredTimeout 客户端配置中的超时。请求未单独设置时使用。
18
+ */
19
+ export declare function buildRedirectOptions(options: HttpRequestOptions, response: HttpResponse, adapter: EClientAdapter, configuredTimeout?: number): HttpRequestOptions | undefined;
20
+ /**
21
+ * 跟跳共用同一次超时。把本跳已经花掉的时间从 redirectOptions.timeout 扣掉。
22
+ * @param redirectOptions 下一跳请求
23
+ * @param startTime 本跳开始时间
24
+ */
25
+ export declare function consumeRedirectTimeout(redirectOptions: HttpRequestOptions, startTime: number): void;
26
+ //# sourceMappingURL=redirect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirect.d.ts","sourceRoot":"","sources":["../../../src/utils/redirect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,kBAAkB,EAClB,YAAY,EACf,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAe1C;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAChC,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,cAAc,EACvB,iBAAiB,CAAC,EAAE,MAAM,GAC3B,kBAAkB,GAAG,SAAS,CA6ChC;AAgDD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAClC,eAAe,EAAE,kBAAkB,EACnC,SAAS,EAAE,MAAM,GAClB,IAAI,CAgBN"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nstarter-http-request",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "nstarter HTTP 请求客户端插件",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -7,16 +7,24 @@ import type {
7
7
  HttpResponse,
8
8
  ProxyConfig
9
9
  } from '../types';
10
- import { HttpError } from '../types';
10
+ import {
11
+ HttpError,
12
+ ResponseTooLargeError
13
+ } from '../types';
11
14
  import { BaseHttpAdapter } from './base';
12
15
  import type {
16
+ AxiosProgressEvent,
13
17
  AxiosProxyConfig,
14
18
  AxiosRequestConfig
15
19
  } from 'axios';
16
20
  import axios from 'axios';
17
21
  import { HttpsProxyAgent } from 'https-proxy-agent';
18
22
  import * as https from 'https';
19
- import { EClientAdapter } from '../const';
23
+ import {
24
+ MAX_RESPONSE_SIZE_TOLERANCE_RATIO,
25
+ EClientAdapter
26
+ } from '../const';
27
+ import { RedirectUtils } from '../utils';
20
28
 
21
29
 
22
30
  /**
@@ -42,7 +50,9 @@ export class AxiosAdapter extends BaseHttpAdapter {
42
50
  }
43
51
 
44
52
  const url = this.buildUrl(options.url, options.params);
53
+ const timeout = options.timeout ?? this.requestConfig.timeout;
45
54
  const axiosConfig = this.buildAxiosConfig(options, url);
55
+ const signalState = this.buildAxiosSignals(axiosConfig, options, timeout);
46
56
 
47
57
  try {
48
58
  const startTime = Date.now();
@@ -67,8 +77,80 @@ export class AxiosAdapter extends BaseHttpAdapter {
67
77
 
68
78
  return response;
69
79
  } catch (error: any) {
70
- throw this.handleAxiosError(error, options);
80
+ throw signalState.abortError() ?? this.handleAxiosError(error, options);
81
+ } finally {
82
+ signalState.cleanup();
83
+ }
84
+ }
85
+
86
+ /**
87
+ * 创建整次请求超时与响应体超限两个中止信号,合并后写入 axiosConfig(原地修改)。
88
+ * 返回 catch 中还原中止原因的 abortError(非本方法中止时返回 undefined),以及 finally 中清理定时器的 cleanup。
89
+ */
90
+ private buildAxiosSignals(axiosConfig: AxiosRequestConfig, options: HttpRequestOptions, timeout?: number): {
91
+ abortError: () => HttpError | undefined,
92
+ cleanup: () => void
93
+ } {
94
+ // maxRedirects 为 0 时 axios 使用原生 http 而不是 follow-redirects。
95
+ // 原生 timeout 是套接字空闲超时,在比如持续上传的场景下会被不断重置,需要使用中止信号来结束请求。
96
+ const deadline = this.createDeadline(timeout);
97
+ const bodySizeGuard = this.createBodySizeGuard(options);
98
+ const signals = [deadline.signal, bodySizeGuard.signal].filter((item): item is AbortSignal => !!item);
99
+ axiosConfig.signal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
100
+ axiosConfig.onDownloadProgress = bodySizeGuard.onDownloadProgress;
101
+
102
+ return {
103
+ abortError: () => {
104
+ if (deadline.timedOut()) {
105
+ return new HttpError(
106
+ `timeout of ${ timeout }ms exceeded`,
107
+ 'ECONNABORTED',
108
+ undefined,
109
+ undefined,
110
+ options
111
+ );
112
+ }
113
+ if (bodySizeGuard.exceeded()) {
114
+ return new ResponseTooLargeError(this.requestConfig.maxResponseBodySize, options);
115
+ }
116
+ return undefined;
117
+ },
118
+ cleanup: deadline.cleanup
119
+ };
120
+ }
121
+
122
+ /**
123
+ * 创建 Content-Length 预检。
124
+ *
125
+ * axios 的 Node http 适配器只按已收到的分块累计 maxContentLength,响应头已声明超限时仍会下载到上限才中断。
126
+ * 这里借助 onDownloadProgress 的 total(响应头 Content-Length),在首个分块到达时就中止请求。
127
+ * - 无 Content-Length(chunked)时不触发,由 axios 的分块累计兜底;
128
+ * - stream 响应不启用,避免额外插入转换流;
129
+ * - total 是线上字节,对几乎不可压缩的 gzip 响应可能略大于解压后的大小,
130
+ * 因此比较时保留 MAX_RESPONSE_SIZE_TOLERANCE_RATIO 的容差。
131
+ */
132
+ private createBodySizeGuard(options: HttpRequestOptions): {
133
+ signal?: AbortSignal,
134
+ onDownloadProgress?: (event: AxiosProgressEvent) => void,
135
+ exceeded: () => boolean
136
+ } {
137
+ const maxRespBodySize = this.resolveMaxResponseBodySize();
138
+ if (options.responseType === 'stream' || maxRespBodySize === undefined) {
139
+ return { exceeded: () => false };
71
140
  }
141
+
142
+ const controller = new AbortController();
143
+ let exceeded = false;
144
+ return {
145
+ signal: controller.signal,
146
+ onDownloadProgress: (event) => {
147
+ if (typeof event.total === 'number' && event.total > maxRespBodySize + Math.ceil(maxRespBodySize * MAX_RESPONSE_SIZE_TOLERANCE_RATIO)) {
148
+ exceeded = true;
149
+ controller.abort();
150
+ }
151
+ },
152
+ exceeded: () => exceeded
153
+ };
72
154
  }
73
155
 
74
156
  /**
@@ -81,14 +163,20 @@ export class AxiosAdapter extends BaseHttpAdapter {
81
163
  method: options.method.toLowerCase(),
82
164
  url,
83
165
  headers: options.headers || {},
84
- timeout: options.timeout ?? this.requestConfig.timeout,
85
166
  maxRedirects: this.requestConfig.maxRedirects,
167
+ validateStatus: (status: number) => {
168
+ return (status >= 200 && status < 300) || status === 304 || RedirectUtils.isRedirectStatus(status);
169
+ },
86
170
  maxContentLength: this.requestConfig.maxResponseBodySize,
87
171
  maxBodyLength: this.requestConfig.maxRequestBodySize,
88
172
  httpsAgent: new https.Agent({
89
173
  rejectUnauthorized: this.securityConfig.rejectUnauthorized
90
174
  })
91
175
  };
176
+ const timeout = options.timeout ?? this.requestConfig.timeout;
177
+ if (timeout !== undefined) {
178
+ axiosConfig.timeout = timeout;
179
+ }
92
180
 
93
181
  // 设置请求体
94
182
  if (options.body !== undefined) {
@@ -178,6 +266,12 @@ export class AxiosAdapter extends BaseHttpAdapter {
178
266
  * @param options 请求选项
179
267
  */
180
268
  private handleAxiosError(error: any, options: HttpRequestOptions): HttpError {
269
+ // axios 没有为 maxContentLength 超限提供专用错误码(与 5xx 共用 ERR_BAD_RESPONSE),
270
+ // 只能靠固定的消息前缀识别,识别后转成不可重试的 ResponseTooLargeError。
271
+ if (error.isAxiosError && error.code === 'ERR_BAD_RESPONSE' && error.message.startsWith('maxContentLength size of')) {
272
+ return new ResponseTooLargeError(this.requestConfig.maxResponseBodySize, options);
273
+ }
274
+
181
275
  if (error.isAxiosError) {
182
276
  return new HttpError(
183
277
  error.message,
@@ -223,4 +317,34 @@ export class AxiosAdapter extends BaseHttpAdapter {
223
317
 
224
318
  return config;
225
319
  }
320
+
321
+ /**
322
+ * 按墙钟时间中止请求,到点后 timedOut 为 true
323
+ * @param timeout 超时时间,单位毫秒
324
+ * @returns 中止信号、是否超时、清理函数
325
+ */
326
+ private createDeadline(timeout?: number): {
327
+ signal?: AbortSignal,
328
+ timedOut: () => boolean,
329
+ cleanup: () => void
330
+ } {
331
+ if (typeof timeout !== 'number' || !Number.isFinite(timeout) || timeout <= 0) {
332
+ return {
333
+ timedOut: () => false,
334
+ cleanup: () => undefined
335
+ };
336
+ }
337
+ const controller = new AbortController();
338
+ let timedOut = false;
339
+ const timer = setTimeout(() => {
340
+ timedOut = true;
341
+ controller.abort();
342
+ }, timeout);
343
+ timer.unref?.();
344
+ return {
345
+ signal: controller.signal,
346
+ timedOut: () => timedOut,
347
+ cleanup: () => clearTimeout(timer)
348
+ };
349
+ }
226
350
  }
@@ -10,11 +10,14 @@ import type {
10
10
  SecurityConfig,
11
11
  ILogger
12
12
  } from '../types';
13
+ import { HttpError } from '../types';
13
14
  import { CommonUtils } from '../utils';
14
15
  import type { EClientAdapter } from '../const';
15
16
 
16
17
  /**
17
18
  * HTTP 适配器抽象基类
19
+ *
20
+ * g-7114106599:不允许直接跟跳3XX,防止SSRF。调用方需要自行处理 3XX 响应。
18
21
  */
19
22
  export abstract class BaseHttpAdapter implements IHttpAdapter {
20
23
  protected requestConfig: RequestConfig;
@@ -22,7 +25,7 @@ export abstract class BaseHttpAdapter implements IHttpAdapter {
22
25
  protected logger?: ILogger;
23
26
 
24
27
  constructor(requestConfig: RequestConfig, securityConfig: SecurityConfig, logger?: ILogger) {
25
- this.requestConfig = requestConfig;
28
+ this.requestConfig = { ...requestConfig, maxRedirects: 0 };
26
29
  this.securityConfig = securityConfig;
27
30
  this.logger = logger;
28
31
  }
@@ -85,6 +88,16 @@ export abstract class BaseHttpAdapter implements IHttpAdapter {
85
88
  error: error instanceof Error ? error.message : String(error)
86
89
  });
87
90
 
91
+ // 默认所有错误均可重试;仅在 HttpError 的 retriable 为 false 时终止重试
92
+ if (error instanceof HttpError && !error.retriable) {
93
+ this.logger?.debug('HTTP request error is not retriable, skip remaining retries', {
94
+ method: options.method,
95
+ url: options.url,
96
+ attempt: attempt + 1
97
+ });
98
+ break;
99
+ }
100
+
88
101
  // 最后一次尝试,不再重试
89
102
  if (attempt === retries) {
90
103
  break;
@@ -106,6 +119,14 @@ export abstract class BaseHttpAdapter implements IHttpAdapter {
106
119
  throw lastError;
107
120
  }
108
121
 
122
+ /**
123
+ * @returns 有效的响应体大小上限;不限制时返回 undefined
124
+ */
125
+ protected resolveMaxResponseBodySize(): number | undefined {
126
+ const max = this.requestConfig.maxResponseBodySize;
127
+ return typeof max === 'number' && max > 0 ? max : undefined;
128
+ }
129
+
109
130
  /**
110
131
  * 更新请求配置
111
132
  * @param config 新的请求配置