@nest-omni/core 4.1.3-22 → 4.1.3-23

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.
@@ -0,0 +1,17 @@
1
+ import { HttpClientConfig } from '../interfaces/http-client-config.interface';
2
+ /**
3
+ * axiosConfig 透传配置示例
4
+ * 展示如何通过 axiosConfig 直接传递 Axios 原生配置
5
+ */
6
+ export declare function httpAgentExample(): void;
7
+ export declare function redirectAndValidationExample(): void;
8
+ export declare function responseTypeExample(): void;
9
+ export declare function sizeAndRateLimitExample(): void;
10
+ export declare function paramsSerializationExample(): void;
11
+ export declare function formSerializationExample(): void;
12
+ export declare function securityOptionsExample(): void;
13
+ export declare function abortControllerExample(): void;
14
+ export declare function transitionalOptionsExample(): void;
15
+ export declare function progressEventsExample(): void;
16
+ export declare function comprehensiveConfigExample(): HttpClientConfig;
17
+ export declare function environmentSpecificConfig(): HttpClientConfig;
@@ -0,0 +1,313 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.httpAgentExample = httpAgentExample;
4
+ exports.redirectAndValidationExample = redirectAndValidationExample;
5
+ exports.responseTypeExample = responseTypeExample;
6
+ exports.sizeAndRateLimitExample = sizeAndRateLimitExample;
7
+ exports.paramsSerializationExample = paramsSerializationExample;
8
+ exports.formSerializationExample = formSerializationExample;
9
+ exports.securityOptionsExample = securityOptionsExample;
10
+ exports.abortControllerExample = abortControllerExample;
11
+ exports.transitionalOptionsExample = transitionalOptionsExample;
12
+ exports.progressEventsExample = progressEventsExample;
13
+ exports.comprehensiveConfigExample = comprehensiveConfigExample;
14
+ exports.environmentSpecificConfig = environmentSpecificConfig;
15
+ const http_1 = require("http");
16
+ const https_1 = require("https");
17
+ /**
18
+ * axiosConfig 透传配置示例
19
+ * 展示如何通过 axiosConfig 直接传递 Axios 原生配置
20
+ */
21
+ // ============================================================================
22
+ // 示例 1: 使用 httpAgent 和 httpsAgent 启用连接池
23
+ // ============================================================================
24
+ function httpAgentExample() {
25
+ const config = {
26
+ baseURL: 'https://api.example.com',
27
+ timeout: 30000,
28
+ // 通过 axiosConfig 透传 Axios 原生配置
29
+ axiosConfig: {
30
+ // 启用 HTTP keep-alive 连接池
31
+ httpAgent: new http_1.Agent({
32
+ keepAlive: true,
33
+ keepAliveMsecs: 1000,
34
+ maxSockets: 50,
35
+ maxFreeSockets: 10,
36
+ timeout: 60000,
37
+ }),
38
+ // 启用 HTTPS keep-alive 连接池
39
+ httpsAgent: new https_1.Agent({
40
+ keepAlive: true,
41
+ keepAliveMsecs: 1000,
42
+ maxSockets: 50,
43
+ maxFreeSockets: 10,
44
+ timeout: 60000,
45
+ // 可选:跳过证书验证(不推荐用于生产环境)
46
+ rejectUnauthorized: true,
47
+ }),
48
+ },
49
+ };
50
+ // 创建 HttpClientService 实例...
51
+ }
52
+ // ============================================================================
53
+ // 示例 2: 配置重定向和响应验证
54
+ // ============================================================================
55
+ function redirectAndValidationExample() {
56
+ const config = {
57
+ baseURL: 'https://api.example.com',
58
+ axiosConfig: {
59
+ // 禁止自动跟随重定向
60
+ maxRedirects: 0,
61
+ // 或者限制重定向次数
62
+ // maxRedirects: 5,
63
+ // 自定义状态码验证逻辑
64
+ validateStatus: (status) => {
65
+ // 将 400-499 视为成功(不抛出异常)
66
+ return status >= 200 && status < 500;
67
+ },
68
+ // 重定向前回调
69
+ beforeRedirect: (options, { headers }) => {
70
+ // 可以在这里修改重定向请求
71
+ if (options.hostname === 'restricted.com') {
72
+ throw new Error('Redirect to restricted domain not allowed');
73
+ }
74
+ },
75
+ },
76
+ };
77
+ }
78
+ // ============================================================================
79
+ // 示例 3: 配置响应类型和数据转换
80
+ // ============================================================================
81
+ function responseTypeExample() {
82
+ const config = {
83
+ baseURL: 'https://api.example.com',
84
+ axiosConfig: {
85
+ // 指定响应类型
86
+ responseType: 'arraybuffer', // 'arraybuffer' | 'document' | 'json' | 'text' | 'stream' | 'blob'
87
+ responseEncoding: 'utf8',
88
+ // 自定义请求/响应转换器
89
+ transformRequest: [
90
+ (data, headers) => {
91
+ // 在发送前修改数据
92
+ if (typeof data === 'object') {
93
+ // 自动添加时间戳
94
+ data.timestamp = Date.now();
95
+ }
96
+ return JSON.stringify(data);
97
+ },
98
+ ...require('axios').defaults.transformRequest,
99
+ ],
100
+ transformResponse: [
101
+ (data) => {
102
+ // 在接收后修改数据
103
+ if (typeof data === 'string') {
104
+ try {
105
+ const parsed = JSON.parse(data);
106
+ // 统一处理响应格式
107
+ return parsed.data || parsed;
108
+ }
109
+ catch (_a) {
110
+ return data;
111
+ }
112
+ }
113
+ return data;
114
+ },
115
+ ...require('axios').defaults.transformResponse,
116
+ ],
117
+ },
118
+ };
119
+ }
120
+ // ============================================================================
121
+ // 示例 4: 配置大小限制和速率限制
122
+ // ============================================================================
123
+ function sizeAndRateLimitExample() {
124
+ const config = {
125
+ baseURL: 'https://api.example.com',
126
+ axiosConfig: {
127
+ // 响应体大小限制(字节)
128
+ maxContentLength: 10 * 1024 * 1024, // 10MB
129
+ // 请求体大小限制(字节)
130
+ maxBodyLength: 5 * 1024 * 1024, // 5MB
131
+ // 速率限制 [上传 B/s, 下载 B/s]
132
+ maxRate: [1024 * 1024, 2 * 1024 * 1024], // 上传 1MB/s, 下载 2MB/s
133
+ },
134
+ };
135
+ }
136
+ // ============================================================================
137
+ // 示例 5: 配置参数序列化
138
+ // ============================================================================
139
+ function paramsSerializationExample() {
140
+ const config = {
141
+ baseURL: 'https://api.example.com',
142
+ axiosConfig: {
143
+ paramsSerializer: {
144
+ // 自定义编码函数
145
+ encode: (param) => {
146
+ return encodeURIComponent(param)
147
+ .replace(/%40/gi, '@')
148
+ .replace(/%3A/gi, ':')
149
+ .replace(/%24/g, '$')
150
+ .replace(/%2C/gi, ',')
151
+ .replace(/%20/g, '+');
152
+ },
153
+ // 数组索引格式
154
+ indexes: true, // true=a[0]=b, false=a[]=b, null=a=b
155
+ },
156
+ },
157
+ };
158
+ }
159
+ // ============================================================================
160
+ // 示例 6: 配置表单序列化
161
+ // ============================================================================
162
+ function formSerializationExample() {
163
+ const config = {
164
+ baseURL: 'https://api.example.com',
165
+ axiosConfig: {
166
+ formSerializer: {
167
+ // 自定义访问器
168
+ visitor: (value, key, path) => {
169
+ // 自定义值转换逻辑
170
+ if (value instanceof Date) {
171
+ return value.toISOString();
172
+ }
173
+ return value;
174
+ },
175
+ // 使用点符号而不是括号
176
+ dots: true,
177
+ // 保留特殊结尾(如 {})
178
+ metaTokens: true,
179
+ // 数组索引格式
180
+ indexes: true,
181
+ },
182
+ },
183
+ };
184
+ }
185
+ // ============================================================================
186
+ // 示例 7: 配置安全选项
187
+ // ============================================================================
188
+ function securityOptionsExample() {
189
+ const config = {
190
+ baseURL: 'https://api.example.com',
191
+ axiosConfig: {
192
+ // 是否允许绝对 URL 覆盖 baseURL
193
+ allowAbsoluteUrls: true,
194
+ // 跨域请求是否携带凭证
195
+ withCredentials: true,
196
+ // 禁用自动解压
197
+ decompress: false,
198
+ // 使用不安全的 HTTP 解析器(允许无效的 HTTP 头)
199
+ // 警告:仅在与非标准 HTTP 实现交互时使用
200
+ insecureHTTPParser: false,
201
+ },
202
+ };
203
+ }
204
+ // ============================================================================
205
+ // 示例 8: 使用 AbortSignal 取消请求
206
+ // ============================================================================
207
+ function abortControllerExample() {
208
+ const config = {
209
+ baseURL: 'https://api.example.com',
210
+ axiosConfig: {
211
+ // 可以在每次请求时动态设置
212
+ // signal: new AbortController().signal,
213
+ },
214
+ };
215
+ // 使用示例:
216
+ // const abortController = new AbortController();
217
+ // config.axiosConfig!.signal = abortController.signal;
218
+ //
219
+ // setTimeout(() => abortController.abort(), 5000); // 5秒后取消
220
+ }
221
+ // ============================================================================
222
+ // 示例 9: 向后兼容选项
223
+ // ============================================================================
224
+ function transitionalOptionsExample() {
225
+ const config = {
226
+ baseURL: 'https://api.example.com',
227
+ axiosConfig: {
228
+ transitional: {
229
+ // 静默 JSON 解析错误(旧行为)
230
+ silentJSONParsing: false,
231
+ // 即使 responseType 不是 'json' 也尝试解析
232
+ forcedJSONParsing: true,
233
+ // 超时时抛出明确的 ETIMEDOUT 错误
234
+ clarifyTimeoutError: true,
235
+ },
236
+ },
237
+ };
238
+ }
239
+ // ============================================================================
240
+ // 示例 10: 进度事件(浏览器环境)
241
+ // ============================================================================
242
+ function progressEventsExample() {
243
+ const config = {
244
+ baseURL: 'https://api.example.com',
245
+ axiosConfig: {
246
+ // 上传进度
247
+ onUploadProgress: (progressEvent) => {
248
+ const percentCompleted = Math.round((progressEvent.loaded * 100) / (progressEvent.total || 1));
249
+ console.log(`Upload ${percentCompleted}%`);
250
+ },
251
+ // 下载进度
252
+ onDownloadProgress: (progressEvent) => {
253
+ const percentCompleted = Math.round((progressEvent.loaded * 100) / (progressEvent.total || 1));
254
+ console.log(`Download ${percentCompleted}%`);
255
+ },
256
+ },
257
+ };
258
+ }
259
+ // ============================================================================
260
+ // 示例 11: 综合配置
261
+ // ============================================================================
262
+ function comprehensiveConfigExample() {
263
+ const config = {
264
+ // 显式配置(优先级高)
265
+ baseURL: 'https://api.example.com',
266
+ timeout: 30000,
267
+ // 内置功能配置
268
+ retry: {
269
+ enabled: true,
270
+ retries: 3,
271
+ },
272
+ circuitBreaker: {
273
+ enabled: true,
274
+ failureThreshold: 5,
275
+ },
276
+ logging: {
277
+ enabled: true,
278
+ logLevel: 'info',
279
+ },
280
+ // Axios 原生配置透传(优先级低,会被显式配置覆盖)
281
+ axiosConfig: {
282
+ httpAgent: new http_1.Agent({ keepAlive: true }),
283
+ httpsAgent: new https_1.Agent({ keepAlive: true }),
284
+ maxRedirects: 5,
285
+ responseType: 'json',
286
+ validateStatus: (status) => status >= 200 && status < 300,
287
+ maxContentLength: 10 * 1024 * 1024,
288
+ },
289
+ };
290
+ return config;
291
+ }
292
+ // ============================================================================
293
+ // 示例 12: 环境相关的配置
294
+ // ============================================================================
295
+ function environmentSpecificConfig() {
296
+ const isDevelopment = process.env.NODE_ENV === 'development';
297
+ const config = {
298
+ baseURL: isDevelopment
299
+ ? 'https://dev-api.example.com'
300
+ : 'https://api.example.com',
301
+ axiosConfig: {
302
+ // 开发环境使用更宽松的验证
303
+ validateStatus: isDevelopment
304
+ ? (status) => status >= 200 && status < 500
305
+ : (status) => status >= 200 && status < 300,
306
+ // 开发环境禁用 keep-alive 以便调试
307
+ httpAgent: isDevelopment
308
+ ? undefined
309
+ : new http_1.Agent({ keepAlive: true }),
310
+ },
311
+ };
312
+ return config;
313
+ }
@@ -1,3 +1,5 @@
1
1
  export * from './basic-usage.example';
2
2
  export * from './advanced-usage.example';
3
3
  export * from './multi-api-configuration.example';
4
+ export * from './axios-config-extended.example';
5
+ export * from './ssl-certificate.example';
@@ -17,3 +17,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./basic-usage.example"), exports);
18
18
  __exportStar(require("./advanced-usage.example"), exports);
19
19
  __exportStar(require("./multi-api-configuration.example"), exports);
20
+ __exportStar(require("./axios-config-extended.example"), exports);
21
+ __exportStar(require("./ssl-certificate.example"), exports);
@@ -0,0 +1,47 @@
1
+ import { HttpClientConfig } from '../index';
2
+ /**
3
+ * SSL/TLS 证书配置示例
4
+ * 解决自签名证书、客户端证书认证等问题
5
+ */
6
+ export declare function disableSslVerificationExample(): void;
7
+ export declare function selfSignedCaExample(): HttpClientConfig;
8
+ export declare function multipleCaCertsExample(): HttpClientConfig;
9
+ export declare function clientCertificateExample(): HttpClientConfig;
10
+ export declare function tlsVersionAndCiphersExample(): HttpClientConfig;
11
+ export declare function certFromEnvExample(): HttpClientConfig;
12
+ export declare function productionSslConfigExample(): HttpClientConfig;
13
+ export declare function environmentBasedSslConfig(): HttpClientConfig;
14
+ export declare function handleCertExpirationExample(): HttpClientConfig;
15
+ export declare function directHttpsAgentExample(): HttpClientConfig;
16
+ export declare function sslErrorHandlingExample(): Promise<void>;
17
+ export declare class DynamicCertificateManager {
18
+ private circuitBreakerService;
19
+ private loggingService;
20
+ private certPaths;
21
+ private httpClient;
22
+ private certCache;
23
+ private lastUpdate;
24
+ private cacheDuration;
25
+ constructor(circuitBreakerService: any, loggingService: any, certPaths: {
26
+ ca?: string;
27
+ cert?: string;
28
+ key?: string;
29
+ });
30
+ private loadCerts;
31
+ private buildConfig;
32
+ refreshCerts(): Promise<void>;
33
+ get(url: string): Promise<void>;
34
+ }
35
+ export declare const sslEnvVars: {
36
+ SSL_CA_PATH: string;
37
+ SSL_CLIENT_CERT_PATH: string;
38
+ SSL_CLIENT_KEY_PATH: string;
39
+ SSL_PASSPHRASE: string;
40
+ SSL_REJECT_UNAUTHORIZED: string;
41
+ SSL_MIN_VERSION: string;
42
+ SSL_CIPHERS: string;
43
+ SSL_CA_CERT: string;
44
+ SSL_CLIENT_CERT: string;
45
+ SSL_CLIENT_KEY: string;
46
+ };
47
+ export declare function diagnoseSslConfig(apiUrl: string): Promise<unknown>;
@@ -0,0 +1,431 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.sslEnvVars = exports.DynamicCertificateManager = void 0;
13
+ exports.disableSslVerificationExample = disableSslVerificationExample;
14
+ exports.selfSignedCaExample = selfSignedCaExample;
15
+ exports.multipleCaCertsExample = multipleCaCertsExample;
16
+ exports.clientCertificateExample = clientCertificateExample;
17
+ exports.tlsVersionAndCiphersExample = tlsVersionAndCiphersExample;
18
+ exports.certFromEnvExample = certFromEnvExample;
19
+ exports.productionSslConfigExample = productionSslConfigExample;
20
+ exports.environmentBasedSslConfig = environmentBasedSslConfig;
21
+ exports.handleCertExpirationExample = handleCertExpirationExample;
22
+ exports.directHttpsAgentExample = directHttpsAgentExample;
23
+ exports.sslErrorHandlingExample = sslErrorHandlingExample;
24
+ exports.diagnoseSslConfig = diagnoseSslConfig;
25
+ const index_1 = require("../index");
26
+ const fs_1 = require("fs");
27
+ const path_1 = require("path");
28
+ /**
29
+ * SSL/TLS 证书配置示例
30
+ * 解决自签名证书、客户端证书认证等问题
31
+ */
32
+ // ============================================================================
33
+ // 示例 1: 禁用证书验证(仅用于开发环境)
34
+ // ============================================================================
35
+ function disableSslVerificationExample() {
36
+ const config = {
37
+ baseURL: 'https://self-signed.example.com',
38
+ timeout: 30000,
39
+ axiosConfig: {
40
+ ssl: {
41
+ // ⚠️ 危险:禁用证书验证,仅用于开发/测试环境
42
+ // 生产环境严禁使用!
43
+ rejectUnauthorized: false,
44
+ },
45
+ },
46
+ };
47
+ // 使用示例
48
+ // const httpClient = new HttpClientService(circuitBreakerService, loggingService, null, config);
49
+ // return httpClient.get('/api/data');
50
+ }
51
+ // ============================================================================
52
+ // 示例 2: 使用自签名 CA 证书(推荐)
53
+ // ============================================================================
54
+ function selfSignedCaExample() {
55
+ // 方式1: 从文件读取 CA 证书
56
+ const caCert = (0, fs_1.readFileSync)((0, path_1.join)(process.cwd(), 'certs/ca.crt'));
57
+ const config = {
58
+ baseURL: 'https://self-signed.example.com',
59
+ timeout: 30000,
60
+ axiosConfig: {
61
+ ssl: {
62
+ // 指定信任的 CA 证书
63
+ ca: caCert,
64
+ // 仍然验证证书,但信任我们的自签名 CA
65
+ rejectUnauthorized: true,
66
+ },
67
+ },
68
+ };
69
+ return config;
70
+ }
71
+ // ============================================================================
72
+ // 示例 3: 使用多个 CA 证书
73
+ // ============================================================================
74
+ function multipleCaCertsExample() {
75
+ const ca1 = (0, fs_1.readFileSync)((0, path_1.join)(process.cwd(), 'certs/ca1.crt'), 'utf8');
76
+ const ca2 = (0, fs_1.readFileSync)((0, path_1.join)(process.cwd(), 'certs/ca2.crt'), 'utf8');
77
+ const ca3 = (0, fs_1.readFileSync)((0, path_1.join)(process.cwd(), 'certs/ca3.crt'), 'utf8');
78
+ const config = {
79
+ baseURL: 'https://multi-ca.example.com',
80
+ timeout: 30000,
81
+ axiosConfig: {
82
+ ssl: {
83
+ // 支持多个 CA 证书
84
+ ca: [ca1, ca2, ca3],
85
+ rejectUnauthorized: true,
86
+ },
87
+ },
88
+ };
89
+ return config;
90
+ }
91
+ // ============================================================================
92
+ // 示例 4: 使用客户端证书(双向 TLS 认证)
93
+ // ============================================================================
94
+ function clientCertificateExample() {
95
+ const caCert = (0, fs_1.readFileSync)((0, path_1.join)(process.cwd(), 'certs/ca.crt'));
96
+ const clientCert = (0, fs_1.readFileSync)((0, path_1.join)(process.cwd(), 'certs/client.crt'));
97
+ const clientKey = (0, fs_1.readFileSync)((0, path_1.join)(process.cwd(), 'certs/client.key'));
98
+ const config = {
99
+ baseURL: 'https://mutual-tls.example.com',
100
+ timeout: 30000,
101
+ axiosConfig: {
102
+ ssl: {
103
+ // CA 证书(验证服务器)
104
+ ca: caCert,
105
+ // 客户端证书(服务器验证客户端)
106
+ cert: clientCert,
107
+ // 客户端私钥
108
+ key: clientKey,
109
+ // 如果私钥有密码
110
+ passphrase: 'your-private-key-password',
111
+ rejectUnauthorized: true,
112
+ },
113
+ },
114
+ };
115
+ return config;
116
+ }
117
+ // ============================================================================
118
+ // 示例 5: 配置 TLS 版本和加密套件
119
+ // ============================================================================
120
+ function tlsVersionAndCiphersExample() {
121
+ const config = {
122
+ baseURL: 'https://secure-api.example.com',
123
+ timeout: 30000,
124
+ axiosConfig: {
125
+ ssl: {
126
+ // 限制 TLS 版本
127
+ minVersion: 'TLSv1.2',
128
+ maxVersion: 'TLSv1.3',
129
+ // 指定加密套件
130
+ ciphers: 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:' +
131
+ 'ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384',
132
+ rejectUnauthorized: true,
133
+ },
134
+ },
135
+ };
136
+ return config;
137
+ }
138
+ // ============================================================================
139
+ // 示例 6: 从环境变量加载证书
140
+ // ============================================================================
141
+ function certFromEnvExample() {
142
+ const config = {
143
+ baseURL: process.env.API_BASE_URL,
144
+ timeout: 30000,
145
+ axiosConfig: {
146
+ ssl: {
147
+ // CA 证书路径或内容
148
+ ca: process.env.SSL_CA_CERT,
149
+ // 客户端证书
150
+ cert: process.env.SSL_CLIENT_CERT,
151
+ // 客户端私钥
152
+ key: process.env.SSL_CLIENT_KEY,
153
+ // 私钥密码
154
+ passphrase: process.env.SSL_PASSPHRASE,
155
+ rejectUnauthorized: true,
156
+ },
157
+ },
158
+ };
159
+ return config;
160
+ }
161
+ // ============================================================================
162
+ // 示例 7: 完整的 SSL 配置(生产环境)
163
+ // ============================================================================
164
+ function productionSslConfigExample() {
165
+ // 在实际应用中,证书应该从安全的配置中心加载
166
+ const caCert = (0, fs_1.readFileSync)(process.env.SSL_CA_PATH || '/etc/ssl/certs/ca.pem');
167
+ const clientCert = (0, fs_1.readFileSync)(process.env.SSL_CLIENT_CERT_PATH || '/etc/ssl/certs/client.pem');
168
+ const clientKey = (0, fs_1.readFileSync)(process.env.SSL_CLIENT_KEY_PATH || '/etc/ssl/private/client.key');
169
+ return {
170
+ baseURL: process.env.API_BASE_URL,
171
+ timeout: 30000,
172
+ // 重试配置
173
+ retry: {
174
+ enabled: true,
175
+ retries: 3,
176
+ },
177
+ // 熔断器配置
178
+ circuitBreaker: {
179
+ enabled: true,
180
+ failureThreshold: 5,
181
+ },
182
+ // 日志配置
183
+ logging: {
184
+ enabled: true,
185
+ logLevel: 'info',
186
+ },
187
+ // SSL 配置
188
+ axiosConfig: {
189
+ ssl: {
190
+ ca: caCert,
191
+ cert: clientCert,
192
+ key: clientKey,
193
+ passphrase: process.env.SSL_PASSPHRASE,
194
+ rejectUnauthorized: true, // 生产环境必须验证证书
195
+ minVersion: 'TLSv1.2', // 最低 TLS 1.2
196
+ },
197
+ },
198
+ };
199
+ }
200
+ // ============================================================================
201
+ // 示例 8: 不同环境使用不同 SSL 配置
202
+ // ============================================================================
203
+ function environmentBasedSslConfig() {
204
+ const isDevelopment = process.env.NODE_ENV === 'development';
205
+ const isTest = process.env.NODE_ENV === 'test';
206
+ const baseConfig = {
207
+ baseURL: process.env.API_BASE_URL,
208
+ timeout: 30000,
209
+ };
210
+ // 开发/测试环境:禁用证书验证
211
+ if (isDevelopment || isTest) {
212
+ baseConfig.axiosConfig = {
213
+ ssl: {
214
+ rejectUnauthorized: false, // 仅用于开发/测试
215
+ },
216
+ };
217
+ }
218
+ else {
219
+ // 生产环境:使用证书验证
220
+ baseConfig.axiosConfig = {
221
+ ssl: {
222
+ ca: (0, fs_1.readFileSync)(process.env.SSL_CA_PATH),
223
+ rejectUnauthorized: true,
224
+ minVersion: 'TLSv1.2',
225
+ },
226
+ };
227
+ }
228
+ return baseConfig;
229
+ }
230
+ // ============================================================================
231
+ // 示例 9: 处理证书过期问题
232
+ // ============================================================================
233
+ function handleCertExpirationExample() {
234
+ const config = {
235
+ baseURL: 'https://api.example.com',
236
+ timeout: 30000,
237
+ axiosConfig: {
238
+ ssl: {
239
+ // 设置服务器名称(SNI)
240
+ servername: 'api.example.com',
241
+ // 如果服务器证书过期但仍需要连接(不推荐)
242
+ rejectUnauthorized: process.env.ALLOW_EXPIRED_CERT === 'true',
243
+ },
244
+ },
245
+ // 重试配置:证书问题通常不需要重试
246
+ retry: {
247
+ enabled: true,
248
+ retries: 1,
249
+ retryCondition: (error) => {
250
+ // 不重试证书错误
251
+ if (error.code === 'CERT_HAS_EXPIRED' ||
252
+ error.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {
253
+ return false;
254
+ }
255
+ return !error.response || error.response.status >= 500;
256
+ },
257
+ },
258
+ };
259
+ return config;
260
+ }
261
+ // ============================================================================
262
+ // 示例 10: 使用 https.Agent 直接配置(兼容旧方式)
263
+ // ============================================================================
264
+ function directHttpsAgentExample() {
265
+ const https = require('https');
266
+ const fs = require('fs');
267
+ // 直接创建 https.Agent
268
+ const httpsAgent = new https.Agent({
269
+ ca: fs.readFileSync('/path/to/ca.crt'),
270
+ cert: fs.readFileSync('/path/to/client.crt'),
271
+ key: fs.readFileSync('/path/to/client.key'),
272
+ rejectUnauthorized: true,
273
+ keepAlive: true,
274
+ });
275
+ const config = {
276
+ baseURL: 'https://api.example.com',
277
+ timeout: 30000,
278
+ axiosConfig: {
279
+ // 直接使用 httpsAgent
280
+ httpsAgent: httpsAgent,
281
+ },
282
+ };
283
+ return config;
284
+ }
285
+ // ============================================================================
286
+ // 示例 11: 错误处理和调试
287
+ // ============================================================================
288
+ function sslErrorHandlingExample() {
289
+ return __awaiter(this, void 0, void 0, function* () {
290
+ const config = {
291
+ baseURL: 'https://self-signed.example.com',
292
+ timeout: 30000,
293
+ axiosConfig: {
294
+ ssl: {
295
+ rejectUnauthorized: true, // 先启用验证
296
+ ca: (0, fs_1.readFileSync)((0, path_1.join)(process.cwd(), 'certs/ca.crt')),
297
+ },
298
+ },
299
+ };
300
+ // const httpClient = new HttpClientService(circuitBreakerService, loggingService, null, config);
301
+ try {
302
+ // return await httpClient.get('/api/data');
303
+ }
304
+ catch (error) {
305
+ // 常见的 SSL 错误码
306
+ switch (error.code) {
307
+ case 'CERT_HAS_EXPIRED':
308
+ console.error('证书已过期');
309
+ break;
310
+ case 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY':
311
+ console.error('无法获取本地颁发者证书,请检查 CA 配置');
312
+ break;
313
+ case 'SELF_SIGNED_CERT_IN_CHAIN':
314
+ console.error('证书链中有自签名证书,请添加 CA 证书');
315
+ break;
316
+ case 'DEPTH_ZERO_SELF_SIGNED_CERT':
317
+ console.error('自签名证书,需要设置 rejectUnauthorized: false 或添加 CA');
318
+ break;
319
+ case 'CERT_REVOKED':
320
+ console.error('证书已被吊销');
321
+ break;
322
+ default:
323
+ console.error('SSL 错误:', error.message);
324
+ }
325
+ throw error;
326
+ }
327
+ });
328
+ }
329
+ // ============================================================================
330
+ // 示例 12: 动态加载证书(支持证书更新)
331
+ // ============================================================================
332
+ class DynamicCertificateManager {
333
+ constructor(circuitBreakerService, loggingService, certPaths) {
334
+ this.circuitBreakerService = circuitBreakerService;
335
+ this.loggingService = loggingService;
336
+ this.certPaths = certPaths;
337
+ this.certCache = {};
338
+ this.lastUpdate = 0;
339
+ this.cacheDuration = 5 * 60 * 1000; // 5分钟
340
+ this.httpClient = new index_1.HttpClientService(this.circuitBreakerService, this.loggingService, null, this.buildConfig());
341
+ }
342
+ loadCerts() {
343
+ const now = Date.now();
344
+ if (now - this.lastUpdate < this.cacheDuration && Object.keys(this.certCache).length > 0) {
345
+ return this.certCache;
346
+ }
347
+ // 重新加载证书
348
+ if (this.certPaths.ca) {
349
+ this.certCache.ca = (0, fs_1.readFileSync)(this.certPaths.ca);
350
+ }
351
+ if (this.certPaths.cert) {
352
+ this.certCache.cert = (0, fs_1.readFileSync)(this.certPaths.cert);
353
+ }
354
+ if (this.certPaths.key) {
355
+ this.certCache.key = (0, fs_1.readFileSync)(this.certPaths.key);
356
+ }
357
+ this.lastUpdate = now;
358
+ return this.certCache;
359
+ }
360
+ buildConfig() {
361
+ const certs = this.loadCerts();
362
+ return {
363
+ baseURL: process.env.API_BASE_URL,
364
+ timeout: 30000,
365
+ axiosConfig: {
366
+ ssl: Object.assign(Object.assign({}, certs), { rejectUnauthorized: true }),
367
+ },
368
+ };
369
+ }
370
+ // 重新创建客户端以使用新证书
371
+ refreshCerts() {
372
+ return __awaiter(this, void 0, void 0, function* () {
373
+ this.lastUpdate = 0;
374
+ const config = this.buildConfig();
375
+ // 在实际应用中,可能需要重新创建 HttpClientService 实例
376
+ // 或者提供更新配置的方法
377
+ });
378
+ }
379
+ get(url) {
380
+ return __awaiter(this, void 0, void 0, function* () {
381
+ // 每次请求前检查是否需要更新证书
382
+ this.loadCerts();
383
+ // return this.httpClient.get(url);
384
+ });
385
+ }
386
+ }
387
+ exports.DynamicCertificateManager = DynamicCertificateManager;
388
+ // ============================================================================
389
+ // 环境变量配置示例
390
+ // ============================================================================
391
+ exports.sslEnvVars = {
392
+ // SSL 配置
393
+ SSL_CA_PATH: '/path/to/ca.crt', // CA 证书文件路径
394
+ SSL_CLIENT_CERT_PATH: '/path/to/client.crt', // 客户端证书文件路径
395
+ SSL_CLIENT_KEY_PATH: '/path/to/client.key', // 客户端私钥文件路径
396
+ SSL_PASSPHRASE: 'your-passphrase', // 私钥密码
397
+ SSL_REJECT_UNAUTHORIZED: 'true', // 是否验证证书(true/false)
398
+ SSL_MIN_VERSION: 'TLSv1.2', // 最低 TLS 版本
399
+ SSL_CIPHERS: 'ECDHE-RSA-AES128-GCM-SHA256:...', // 加密套件
400
+ // 或者直接提供证书内容
401
+ SSL_CA_CERT: '-----BEGIN CERTIFICATE-----\n...', // CA 证书内容
402
+ SSL_CLIENT_CERT: '-----BEGIN CERTIFICATE-----\n...', // 客户端证书内容
403
+ SSL_CLIENT_KEY: '-----BEGIN PRIVATE KEY-----\n...', // 客户端私钥内容
404
+ };
405
+ // ============================================================================
406
+ // 快速诊断脚本
407
+ // ============================================================================
408
+ function diagnoseSslConfig(apiUrl) {
409
+ return __awaiter(this, void 0, void 0, function* () {
410
+ const https = require('https');
411
+ return new Promise((resolve, reject) => {
412
+ const req = https.get(apiUrl, (res) => {
413
+ const cert = res.socket.getPeerCertificate();
414
+ console.log('服务器证书信息:');
415
+ console.log(' 主题:', cert.subject);
416
+ console.log(' 颁发者:', cert.issuer);
417
+ console.log(' 有效期:', new Date(cert.valid_from), '至', new Date(cert.valid_to));
418
+ console.log(' 序列号:', cert.serialNumber);
419
+ resolve(cert);
420
+ });
421
+ req.on('error', (error) => {
422
+ console.error('SSL 连接失败:', error.code, error.message);
423
+ reject(error);
424
+ });
425
+ });
426
+ });
427
+ }
428
+ // 使用示例:
429
+ // diagnoseSslConfig('https://self-signed.example.com')
430
+ // .then(cert => console.log('证书 OK'))
431
+ // .catch(err => console.log('证书错误'));
@@ -1,4 +1,4 @@
1
- export { HttpClientConfig, RetryConfig, CircuitBreakerConfig, ProxyConfig, LoggingConfig, InterceptorConfig, ConnectionPoolConfig, HttpContext, HttpInterceptor, HttpMethod, HttpStats, } from './interfaces/http-client-config.interface';
1
+ export { HttpClientConfig, AxiosNativeConfig, SslCertificateConfig, RetryConfig, CircuitBreakerConfig, ProxyConfig, LoggingConfig, InterceptorConfig, ConnectionPoolConfig, HttpContext, HttpInterceptor, HttpMethod, HttpStats, } from './interfaces/http-client-config.interface';
2
2
  export * from './interfaces/api-client-config.interface';
3
3
  export { HttpLogEntity, RetryRecord } from './entities';
4
4
  export * from './decorators';
@@ -1,6 +1,73 @@
1
1
  import { AxiosRequestConfig, AxiosResponse } from 'axios';
2
2
  import { LogCleanupConfig } from '../services/log-cleanup.service';
3
3
  import { SSRFProtectionConfig, URLValidationConfig } from '../utils/security-validator.util';
4
+ import type { AgentOptions } from 'https';
5
+ /**
6
+ * SSL/TLS 证书配置
7
+ * 兼容 Node.js https.Agent 的选项
8
+ * 参考: https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options
9
+ */
10
+ export interface SslCertificateConfig extends Partial<Omit<AgentOptions, 'host' | 'port' | 'path'>> {
11
+ /**
12
+ * 是否禁用证书验证(仅用于开发/测试环境)
13
+ * 警告:设置为 true 会使连接不安全,生产环境严禁使用
14
+ */
15
+ rejectUnauthorized?: boolean;
16
+ /**
17
+ * CA 证书内容(PEM 格式)
18
+ * 可以是单个证书或多个证书的字符串
19
+ */
20
+ ca?: string | string[] | Buffer;
21
+ /**
22
+ * 客户端证书内容(PEM 格式)
23
+ */
24
+ cert?: string | string[] | Buffer;
25
+ /**
26
+ * 客户端私钥内容(PEM 格式)
27
+ */
28
+ key?: string | string[] | Buffer;
29
+ /**
30
+ * 私钥密码
31
+ */
32
+ passphrase?: string;
33
+ /**
34
+ * 服务器名称(用于 SNI)
35
+ */
36
+ servername?: string;
37
+ /**
38
+ * 支持的 TLS 版本
39
+ */
40
+ minVersion?: 'TLSv1' | 'TLSv1.1' | 'TLSv1.2' | 'TLSv1.3';
41
+ maxVersion?: 'TLSv1' | 'TLSv1.1' | 'TLSv1.2' | 'TLSv1.3';
42
+ /**
43
+ * 支持的加密套件
44
+ */
45
+ ciphers?: string;
46
+ /**
47
+ * 是否支持 DH 参数
48
+ */
49
+ dhparam?: string | Buffer;
50
+ /**
51
+ * 是否使用安全 renegotiation
52
+ */
53
+ secureOptions?: number;
54
+ }
55
+ /**
56
+ * Axios 原生配置透传
57
+ * 基于 AxiosRequestConfig,排除已在 HttpClientConfig 中定义的字段
58
+ *
59
+ * 使用方式:
60
+ * - 直接传 Axios 原生配置对象
61
+ * - 类型安全,支持所有 Axios 配置项
62
+ * - ssl 配置会被自动转换为 httpsAgent
63
+ */
64
+ export type AxiosNativeConfig = Omit<AxiosRequestConfig, 'baseURL' | 'timeout' | 'proxy' | 'url' | 'method' | 'data' | 'headers' | 'params'> & {
65
+ /**
66
+ * SSL/TLS 证书配置(简化版)
67
+ * 会自动转换为 httpsAgent,优先级高于直接指定的 httpsAgent
68
+ */
69
+ ssl?: SslCertificateConfig;
70
+ };
4
71
  /**
5
72
  * HTTP客户端配置接口
6
73
  * 基于Spring Boot的@ConfigurationProperties设计理念
@@ -33,6 +100,12 @@ export interface HttpClientConfig {
33
100
  /** 是否启用安全验证 */
34
101
  enabled?: boolean;
35
102
  };
103
+ /**
104
+ * Axios 原生配置透传
105
+ * 用于直接传递 Axios 支持的任何配置项,提供最大灵活性
106
+ * 优先级低于上述显式配置,会进行深度合并
107
+ */
108
+ axiosConfig?: AxiosNativeConfig;
36
109
  }
37
110
  /**
38
111
  * 重试配置
@@ -17,6 +17,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
17
17
  step((generator = generator.apply(thisArg, _arguments || [])).next());
18
18
  });
19
19
  };
20
+ var __rest = (this && this.__rest) || function (s, e) {
21
+ var t = {};
22
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
23
+ t[p] = s[p];
24
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
25
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
26
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
27
+ t[p[i]] = s[p[i]];
28
+ }
29
+ return t;
30
+ };
20
31
  var HttpClientService_1;
21
32
  Object.defineProperty(exports, "__esModule", { value: true });
22
33
  exports.HttpClientService = void 0;
@@ -436,14 +447,44 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
436
447
  * 创建Axios实例并配置axios-retry
437
448
  */
438
449
  createAxiosInstance() {
439
- var _a;
440
- const instance = require('axios').create({
450
+ var _a, _b, _c;
451
+ // 合并代理配置和 axiosConfig 透传配置
452
+ const resolvedProxy = this.resolveProxyConfig(this.defaultConfig.proxy);
453
+ // 处理 SSL 配置和 httpsAgent
454
+ let httpsAgent = (_a = this.defaultConfig.axiosConfig) === null || _a === void 0 ? void 0 : _a.httpsAgent;
455
+ if ((_b = this.defaultConfig.axiosConfig) === null || _b === void 0 ? void 0 : _b.ssl) {
456
+ const ssl = this.defaultConfig.axiosConfig.ssl;
457
+ const https = require('https');
458
+ if (!httpsAgent) {
459
+ // 如果没有预定义的 httpsAgent,使用 SSL 配置创建
460
+ httpsAgent = new https.Agent(Object.assign(Object.assign({}, ssl), { keepAlive: true }));
461
+ }
462
+ else {
463
+ // 如果同时提供了 httpsAgent 和 ssl 配置
464
+ // ssl 配置会覆盖 httpsAgent 的相关选项
465
+ this.logger.warn('Both httpsAgent and ssl config provided. SSL config will take precedence for certificate options.');
466
+ // 创建新的 Agent,合并原有配置和 SSL 配置
467
+ httpsAgent = new https.Agent(Object.assign({
468
+ // 保留原 Agent 的选项(除了证书相关)
469
+ keepAlive: true }, ssl));
470
+ }
471
+ }
472
+ // 构建 axios 创建配置
473
+ const axiosCreateConfig = {
441
474
  baseURL: this.defaultConfig.baseURL,
442
475
  timeout: this.defaultConfig.timeout,
443
- proxy: this.resolveProxyConfig(this.defaultConfig.proxy),
444
- });
476
+ proxy: resolvedProxy !== undefined ? resolvedProxy : undefined,
477
+ // 应用处理后的 httpsAgent
478
+ httpsAgent: httpsAgent,
479
+ };
480
+ // 透传所有其他 axiosConfig 配置(排除已特殊处理的字段)
481
+ if (this.defaultConfig.axiosConfig) {
482
+ const _d = this.defaultConfig.axiosConfig, { ssl, httpsAgent: _ } = _d, restAxiosConfig = __rest(_d, ["ssl", "httpsAgent"]);
483
+ Object.assign(axiosCreateConfig, restAxiosConfig);
484
+ }
485
+ const instance = require('axios').create(axiosCreateConfig);
445
486
  // 配置axios-retry
446
- if ((_a = this.defaultConfig.retry) === null || _a === void 0 ? void 0 : _a.enabled) {
487
+ if ((_c = this.defaultConfig.retry) === null || _c === void 0 ? void 0 : _c.enabled) {
447
488
  (0, axios_retry_1.default)(instance, {
448
489
  retries: this.defaultConfig.retry.retries || 3,
449
490
  retryDelay: this.defaultConfig.retry.retryDelay ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nest-omni/core",
3
- "version": "4.1.3-22",
3
+ "version": "4.1.3-23",
4
4
  "description": "A comprehensive NestJS framework for building enterprise-grade applications with best practices",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",