@nest-omni/core 4.1.3-25 → 4.1.3-27
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/cache/cache.service.d.ts +3 -1
- package/cache/cache.service.js +8 -8
- package/cache/decorators/cache-put.decorator.js +5 -4
- package/cache/dependencies/callback.dependency.js +9 -0
- package/cache/dependencies/tag.dependency.d.ts +1 -9
- package/cache/dependencies/tag.dependency.js +5 -14
- package/cache/providers/lrucache.provider.d.ts +1 -0
- package/cache/providers/lrucache.provider.js +6 -4
- package/cache/providers/redis-cache.provider.d.ts +1 -0
- package/cache/providers/redis-cache.provider.js +8 -6
- package/http-client/config/http-client.config.js +4 -2
- package/http-client/decorators/http-client.decorators.d.ts +1 -1
- package/http-client/decorators/http-client.decorators.js +1 -1
- package/http-client/examples/advanced-usage.example.js +3 -3
- package/http-client/examples/axios-config-extended.example.js +1 -3
- package/http-client/examples/flexible-response-example.d.ts +28 -0
- package/http-client/examples/flexible-response-example.js +120 -0
- package/http-client/examples/ssl-certificate.example.d.ts +2 -2
- package/http-client/examples/ssl-certificate.example.js +18 -17
- package/http-client/http-client.module.js +2 -2
- package/http-client/interfaces/http-client-config.interface.d.ts +6 -1
- package/http-client/services/api-client-registry.service.d.ts +6 -6
- package/http-client/services/api-client-registry.service.js +9 -9
- package/http-client/services/circuit-breaker.service.d.ts +9 -9
- package/http-client/services/circuit-breaker.service.js +24 -24
- package/http-client/services/http-client.service.d.ts +30 -13
- package/http-client/services/http-client.service.js +76 -47
- package/http-client/services/logging.service.d.ts +17 -33
- package/http-client/services/logging.service.js +81 -169
- package/http-client/utils/curl-generator.util.js +2 -5
- package/http-client/utils/index.d.ts +1 -0
- package/http-client/utils/index.js +1 -0
- package/http-client/utils/proxy-environment.util.d.ts +12 -12
- package/http-client/utils/proxy-environment.util.js +25 -19
- package/http-client/utils/retry-recorder.util.d.ts +0 -4
- package/http-client/utils/retry-recorder.util.js +2 -27
- package/http-client/utils/sanitize.util.d.ts +58 -0
- package/http-client/utils/sanitize.util.js +188 -0
- package/http-client/utils/security-validator.util.d.ts +19 -19
- package/http-client/utils/security-validator.util.js +66 -64
- package/interceptors/http-logging-interceptor.service.d.ts +38 -0
- package/interceptors/http-logging-interceptor.service.js +167 -0
- package/interceptors/index.d.ts +1 -0
- package/interceptors/index.js +1 -0
- package/package.json +1 -1
- package/setup/bootstrap.setup.js +1 -1
- package/shared/services/api-config.service.js +3 -18
- package/vault/vault-config.service.js +1 -1
|
@@ -166,7 +166,12 @@ export interface LoggingConfig {
|
|
|
166
166
|
logHeaders?: boolean;
|
|
167
167
|
logBody?: boolean;
|
|
168
168
|
maxBodyLength?: number;
|
|
169
|
-
|
|
169
|
+
/**
|
|
170
|
+
* 脱敏配置
|
|
171
|
+
* 敏感字段列表,统一适用于 headers、body、query string
|
|
172
|
+
* 例如:['password', 'token', 'secret', 'apiKey']
|
|
173
|
+
*/
|
|
174
|
+
sanitize?: string[];
|
|
170
175
|
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
|
171
176
|
databaseLogging?: {
|
|
172
177
|
enabled?: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ApiClientConfig, ApiClientInstanceConfig, ApiClientRegistryConfig, AuthType, ResponseTransformerConfig } from '../interfaces/api-client-config.interface';
|
|
2
2
|
import { HttpCircuitBreakerService } from './circuit-breaker.service';
|
|
3
3
|
import { HttpLoggingService } from './logging.service';
|
|
4
|
-
export { ApiClientInstanceConfig, AuthType, ResponseTransformerConfig
|
|
4
|
+
export { ApiClientInstanceConfig, AuthType, ResponseTransformerConfig };
|
|
5
5
|
/**
|
|
6
6
|
* API客户端注册服务
|
|
7
7
|
* 负责管理多个 HttpClientService 实例
|
|
@@ -19,11 +19,6 @@ export declare class ApiClientRegistryService {
|
|
|
19
19
|
* 使用 HttpClientService.createApiClient 静态方法创建
|
|
20
20
|
*/
|
|
21
21
|
createClient<T = any>(config: ApiClientInstanceConfig): T;
|
|
22
|
-
/**
|
|
23
|
-
* 深度合并配置(已废弃,不再需要)
|
|
24
|
-
* @deprecated 配置结构简化后不再需要此方法
|
|
25
|
-
*/
|
|
26
|
-
private deepMergeConfigs;
|
|
27
22
|
/**
|
|
28
23
|
* 获取已注册的客户端
|
|
29
24
|
*/
|
|
@@ -78,6 +73,11 @@ export declare class ApiClientRegistryService {
|
|
|
78
73
|
error?: string;
|
|
79
74
|
}>;
|
|
80
75
|
}>;
|
|
76
|
+
/**
|
|
77
|
+
* 深度合并配置(已废弃,不再需要)
|
|
78
|
+
* @deprecated 配置结构简化后不再需要此方法
|
|
79
|
+
*/
|
|
80
|
+
private deepMergeConfigs;
|
|
81
81
|
/**
|
|
82
82
|
* 合并环境特定配置
|
|
83
83
|
*/
|
|
@@ -47,7 +47,7 @@ let ApiClientRegistryService = ApiClientRegistryService_1 = class ApiClientRegis
|
|
|
47
47
|
logHeaders: true,
|
|
48
48
|
logBody: true,
|
|
49
49
|
maxBodyLength: 10000,
|
|
50
|
-
|
|
50
|
+
sanitize: ['authorization', 'api-key'],
|
|
51
51
|
logLevel: 'info',
|
|
52
52
|
},
|
|
53
53
|
timeout: 30000,
|
|
@@ -74,7 +74,7 @@ let ApiClientRegistryService = ApiClientRegistryService_1 = class ApiClientRegis
|
|
|
74
74
|
// 1. 从全局默认配置开始
|
|
75
75
|
// 2. 合并 ApiClient 的 httpConfig
|
|
76
76
|
// 3. 应用 ApiClient 特有的 retry 配置(兼容旧代码)
|
|
77
|
-
|
|
77
|
+
const mergedHttpConfig = Object.assign(Object.assign({}, this.globalDefaults.globalDefaults), finalConfig.httpConfig);
|
|
78
78
|
// 兼容:如果 ApiClientConfig 顶层有 retry 配置,合并到 httpConfig.retry
|
|
79
79
|
if (finalConfig.retry) {
|
|
80
80
|
mergedHttpConfig.retry = Object.assign(Object.assign({}, mergedHttpConfig.retry), finalConfig.retry);
|
|
@@ -95,13 +95,6 @@ let ApiClientRegistryService = ApiClientRegistryService_1 = class ApiClientRegis
|
|
|
95
95
|
this.logger.log(`Created API client: ${clientName}`);
|
|
96
96
|
return httpClient;
|
|
97
97
|
}
|
|
98
|
-
/**
|
|
99
|
-
* 深度合并配置(已废弃,不再需要)
|
|
100
|
-
* @deprecated 配置结构简化后不再需要此方法
|
|
101
|
-
*/
|
|
102
|
-
deepMergeConfigs(defaults, userConfig) {
|
|
103
|
-
return Object.assign(Object.assign({}, defaults), userConfig);
|
|
104
|
-
}
|
|
105
98
|
/**
|
|
106
99
|
* 获取已注册的客户端
|
|
107
100
|
*/
|
|
@@ -226,6 +219,13 @@ let ApiClientRegistryService = ApiClientRegistryService_1 = class ApiClientRegis
|
|
|
226
219
|
};
|
|
227
220
|
});
|
|
228
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* 深度合并配置(已废弃,不再需要)
|
|
224
|
+
* @deprecated 配置结构简化后不再需要此方法
|
|
225
|
+
*/
|
|
226
|
+
deepMergeConfigs(defaults, userConfig) {
|
|
227
|
+
return Object.assign(Object.assign({}, defaults), userConfig);
|
|
228
|
+
}
|
|
229
229
|
/**
|
|
230
230
|
* 合并环境特定配置
|
|
231
231
|
*/
|
|
@@ -55,15 +55,6 @@ export declare class HttpCircuitBreakerService {
|
|
|
55
55
|
* 清理超过最大空闲时间的Circuit Breaker
|
|
56
56
|
*/
|
|
57
57
|
cleanupIdle(): number;
|
|
58
|
-
/**
|
|
59
|
-
* 基于LRU策略清理Circuit Breaker
|
|
60
|
-
* 删除最久未访问的Circuit Breaker直到数量降到maxSize以下
|
|
61
|
-
*/
|
|
62
|
-
private cleanupLRU;
|
|
63
|
-
/**
|
|
64
|
-
* 启动定期清理任务
|
|
65
|
-
*/
|
|
66
|
-
private startCleanupTask;
|
|
67
58
|
/**
|
|
68
59
|
* 手动触发清理(用于测试)
|
|
69
60
|
*/
|
|
@@ -76,6 +67,15 @@ export declare class HttpCircuitBreakerService {
|
|
|
76
67
|
* 获取清理配置
|
|
77
68
|
*/
|
|
78
69
|
getCleanupConfig(): CircuitBreakerCleanupConfig;
|
|
70
|
+
/**
|
|
71
|
+
* 基于LRU策略清理Circuit Breaker
|
|
72
|
+
* 删除最久未访问的Circuit Breaker直到数量降到maxSize以下
|
|
73
|
+
*/
|
|
74
|
+
private cleanupLRU;
|
|
75
|
+
/**
|
|
76
|
+
* 启动定期清理任务
|
|
77
|
+
*/
|
|
78
|
+
private startCleanupTask;
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
81
|
* 熔断器类
|
|
@@ -160,6 +160,30 @@ let HttpCircuitBreakerService = HttpCircuitBreakerService_1 = class HttpCircuitB
|
|
|
160
160
|
}
|
|
161
161
|
return keysToDelete.length;
|
|
162
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* 手动触发清理(用于测试)
|
|
165
|
+
*/
|
|
166
|
+
manualCleanup() {
|
|
167
|
+
return this.cleanupIdle();
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* 设置清理配置
|
|
171
|
+
*/
|
|
172
|
+
setCleanupConfig(config) {
|
|
173
|
+
Object.assign(this.cleanupConfig, config);
|
|
174
|
+
// 重启清理任务
|
|
175
|
+
if (this.cleanupTimer) {
|
|
176
|
+
clearInterval(this.cleanupTimer);
|
|
177
|
+
}
|
|
178
|
+
this.startCleanupTask();
|
|
179
|
+
this.logger.log(`Circuit breaker cleanup config updated: ${JSON.stringify(this.cleanupConfig)}`);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* 获取清理配置
|
|
183
|
+
*/
|
|
184
|
+
getCleanupConfig() {
|
|
185
|
+
return Object.assign({}, this.cleanupConfig);
|
|
186
|
+
}
|
|
163
187
|
/**
|
|
164
188
|
* 基于LRU策略清理Circuit Breaker
|
|
165
189
|
* 删除最久未访问的Circuit Breaker直到数量降到maxSize以下
|
|
@@ -194,30 +218,6 @@ let HttpCircuitBreakerService = HttpCircuitBreakerService_1 = class HttpCircuitB
|
|
|
194
218
|
}, this.cleanupConfig.cleanupIntervalMs);
|
|
195
219
|
this.logger.log(`Circuit breaker cleanup task started (interval: ${this.cleanupConfig.cleanupIntervalMs}ms, maxIdleTime: ${this.cleanupConfig.maxIdleTimeMs}ms)`);
|
|
196
220
|
}
|
|
197
|
-
/**
|
|
198
|
-
* 手动触发清理(用于测试)
|
|
199
|
-
*/
|
|
200
|
-
manualCleanup() {
|
|
201
|
-
return this.cleanupIdle();
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* 设置清理配置
|
|
205
|
-
*/
|
|
206
|
-
setCleanupConfig(config) {
|
|
207
|
-
Object.assign(this.cleanupConfig, config);
|
|
208
|
-
// 重启清理任务
|
|
209
|
-
if (this.cleanupTimer) {
|
|
210
|
-
clearInterval(this.cleanupTimer);
|
|
211
|
-
}
|
|
212
|
-
this.startCleanupTask();
|
|
213
|
-
this.logger.log(`Circuit breaker cleanup config updated: ${JSON.stringify(this.cleanupConfig)}`);
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* 获取清理配置
|
|
217
|
-
*/
|
|
218
|
-
getCleanupConfig() {
|
|
219
|
-
return Object.assign({}, this.cleanupConfig);
|
|
220
|
-
}
|
|
221
221
|
};
|
|
222
222
|
exports.HttpCircuitBreakerService = HttpCircuitBreakerService;
|
|
223
223
|
exports.HttpCircuitBreakerService = HttpCircuitBreakerService = HttpCircuitBreakerService_1 = __decorate([
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
2
2
|
import { HttpClientConfig } from '../interfaces/http-client-config.interface';
|
|
3
|
-
import {
|
|
3
|
+
import { ApiKeyConfig, AuthType, BasicAuthConfig, BearerTokenConfig, CustomAuthConfig, OAuth2Config } from '../interfaces/api-client-config.interface';
|
|
4
4
|
import { HttpCircuitBreakerService } from './circuit-breaker.service';
|
|
5
5
|
import { HttpLoggingService } from './logging.service';
|
|
6
6
|
import { RedisLockService } from '../../redis-lock/redis-lock.service';
|
|
@@ -11,6 +11,15 @@ interface ExtendedAxiosRequestConfig extends AxiosRequestConfig {
|
|
|
11
11
|
[key: string]: any;
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* 请求返回选项
|
|
16
|
+
*/
|
|
17
|
+
interface RequestReturnOptions {
|
|
18
|
+
/** 返回类型: 'data'(默认) | 'full' | 'custom' */
|
|
19
|
+
returnType?: 'data' | 'full' | 'custom';
|
|
20
|
+
/** 自定义返回转换函数 */
|
|
21
|
+
transform?: (response: AxiosResponse) => any;
|
|
22
|
+
}
|
|
14
23
|
/**
|
|
15
24
|
* 认证配置接口
|
|
16
25
|
*/
|
|
@@ -55,8 +64,16 @@ export declare class HttpClientService {
|
|
|
55
64
|
}): HttpClientService;
|
|
56
65
|
/**
|
|
57
66
|
* 执行HTTP请求
|
|
67
|
+
* @param config 请求配置
|
|
68
|
+
* @param decoratorContext 装饰器上下文
|
|
69
|
+
* @param clientName 客户端名称
|
|
70
|
+
* @param returnOptions 返回选项
|
|
71
|
+
* - returnType: 'data'(默认)只返回response.data
|
|
72
|
+
* - returnType: 'full'返回完整AxiosResponse对象
|
|
73
|
+
* - returnType: 'custom'使用自定义转换函数
|
|
74
|
+
* - transform: 自定义转换函数,接收完整response返回任意数据
|
|
58
75
|
*/
|
|
59
|
-
request<T = any>(config: ExtendedAxiosRequestConfig, decoratorContext?: any, clientName?: string): Promise<T>;
|
|
76
|
+
request<T = any>(config: ExtendedAxiosRequestConfig, decoratorContext?: any, clientName?: string, returnOptions?: RequestReturnOptions): Promise<T>;
|
|
60
77
|
/**
|
|
61
78
|
* 生成curl命令(动态生成,不存储)
|
|
62
79
|
*/
|
|
@@ -77,16 +94,11 @@ export declare class HttpClientService {
|
|
|
77
94
|
* 获取客户端名称
|
|
78
95
|
*/
|
|
79
96
|
getName(): string | undefined;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
get<T = any>(url: string, config?: AxiosRequestConfig, clientName?: string): Promise<T>;
|
|
86
|
-
post<T = any>(url: string, data?: any, config?: AxiosRequestConfig, clientName?: string): Promise<T>;
|
|
87
|
-
put<T = any>(url: string, data?: any, config?: AxiosRequestConfig, clientName?: string): Promise<T>;
|
|
88
|
-
patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig, clientName?: string): Promise<T>;
|
|
89
|
-
delete<T = any>(url: string, config?: AxiosRequestConfig, clientName?: string): Promise<T>;
|
|
97
|
+
get<T = any>(url: string, config?: AxiosRequestConfig, clientName?: string, returnOptions?: RequestReturnOptions): Promise<T>;
|
|
98
|
+
post<T = any>(url: string, data?: any, config?: AxiosRequestConfig, clientName?: string, returnOptions?: RequestReturnOptions): Promise<T>;
|
|
99
|
+
put<T = any>(url: string, data?: any, config?: AxiosRequestConfig, clientName?: string, returnOptions?: RequestReturnOptions): Promise<T>;
|
|
100
|
+
patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig, clientName?: string, returnOptions?: RequestReturnOptions): Promise<T>;
|
|
101
|
+
delete<T = any>(url: string, config?: AxiosRequestConfig, clientName?: string, returnOptions?: RequestReturnOptions): Promise<T>;
|
|
90
102
|
/**
|
|
91
103
|
* 带等待锁的认证请求方法
|
|
92
104
|
* 用于需要确保只有一个进程执行认证相关操作的场景
|
|
@@ -101,7 +113,7 @@ export declare class HttpClientService {
|
|
|
101
113
|
lockTimeout?: number;
|
|
102
114
|
waitTimeout?: number;
|
|
103
115
|
enableRetry?: boolean;
|
|
104
|
-
}, clientName?: string): Promise<T>;
|
|
116
|
+
}, clientName?: string, returnOptions?: RequestReturnOptions): Promise<T>;
|
|
105
117
|
/**
|
|
106
118
|
* 带等待锁的批量认证请求
|
|
107
119
|
* 用于需要批量执行认证相关操作但避免重复认证的场景
|
|
@@ -120,6 +132,11 @@ export declare class HttpClientService {
|
|
|
120
132
|
waitTimeout?: number;
|
|
121
133
|
maxConcurrency?: number;
|
|
122
134
|
}, clientName?: string): Promise<Array<T | null>>;
|
|
135
|
+
/**
|
|
136
|
+
* Capture calling context information
|
|
137
|
+
* @returns Calling context with service class and method name
|
|
138
|
+
*/
|
|
139
|
+
private captureCallingContext;
|
|
123
140
|
/**
|
|
124
141
|
* 创建Axios实例并配置axios-retry
|
|
125
142
|
*/
|
|
@@ -92,8 +92,16 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
92
92
|
}
|
|
93
93
|
/**
|
|
94
94
|
* 执行HTTP请求
|
|
95
|
+
* @param config 请求配置
|
|
96
|
+
* @param decoratorContext 装饰器上下文
|
|
97
|
+
* @param clientName 客户端名称
|
|
98
|
+
* @param returnOptions 返回选项
|
|
99
|
+
* - returnType: 'data'(默认)只返回response.data
|
|
100
|
+
* - returnType: 'full'返回完整AxiosResponse对象
|
|
101
|
+
* - returnType: 'custom'使用自定义转换函数
|
|
102
|
+
* - transform: 自定义转换函数,接收完整response返回任意数据
|
|
95
103
|
*/
|
|
96
|
-
request(config, decoratorContext, clientName) {
|
|
104
|
+
request(config, decoratorContext, clientName, returnOptions) {
|
|
97
105
|
return __awaiter(this, void 0, void 0, function* () {
|
|
98
106
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
99
107
|
// Use the instance's clientName as fallback if not provided
|
|
@@ -107,7 +115,10 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
107
115
|
const baseURL = config.baseURL || this.defaultConfig.baseURL || '';
|
|
108
116
|
// 构建完整的URL用于验证
|
|
109
117
|
let fullURL = requestURL;
|
|
110
|
-
if (requestURL &&
|
|
118
|
+
if (requestURL &&
|
|
119
|
+
!requestURL.startsWith('http://') &&
|
|
120
|
+
!requestURL.startsWith('https://') &&
|
|
121
|
+
baseURL) {
|
|
111
122
|
// 处理相对URL
|
|
112
123
|
try {
|
|
113
124
|
fullURL = new URL(requestURL, baseURL).href;
|
|
@@ -118,7 +129,8 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
118
129
|
}
|
|
119
130
|
}
|
|
120
131
|
// 执行URL安全验证(只对完整URL进行验证)
|
|
121
|
-
if (fullURL &&
|
|
132
|
+
if (fullURL &&
|
|
133
|
+
(fullURL.startsWith('http://') || fullURL.startsWith('https://'))) {
|
|
122
134
|
const sanitizeResult = security_validator_util_1.SecurityValidator.sanitizeURL(fullURL, {
|
|
123
135
|
urlConfig: (_a = this.defaultConfig.security) === null || _a === void 0 ? void 0 : _a.urlValidation,
|
|
124
136
|
ssrfConfig: (_b = this.defaultConfig.security) === null || _b === void 0 ? void 0 : _b.ssrfProtection,
|
|
@@ -143,7 +155,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
143
155
|
let circuitBreakerState;
|
|
144
156
|
try {
|
|
145
157
|
// 应用认证配置
|
|
146
|
-
|
|
158
|
+
const authConfig = yield this.applyAuthToConfig(config);
|
|
147
159
|
// 应用装饰器配置
|
|
148
160
|
const enhancedConfig = this.applyDecoratorConfig(authConfig, decoratorContext);
|
|
149
161
|
// 将 retryRecorder 存储到 config metadata 中,供 onRetry 回调使用
|
|
@@ -191,7 +203,24 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
191
203
|
}
|
|
192
204
|
// 更新统计信息
|
|
193
205
|
this.updateRequestStats(true, Date.now() - startTime, ((_f = response.config) === null || _f === void 0 ? void 0 : _f.method) || 'GET', response.status);
|
|
194
|
-
|
|
206
|
+
// 根据返回选项处理响应
|
|
207
|
+
const options = returnOptions || { returnType: 'data' };
|
|
208
|
+
switch (options.returnType) {
|
|
209
|
+
case 'full':
|
|
210
|
+
// 返回完整响应对象
|
|
211
|
+
return response;
|
|
212
|
+
case 'custom':
|
|
213
|
+
// 使用自定义转换函数
|
|
214
|
+
if (options.transform) {
|
|
215
|
+
return options.transform(response);
|
|
216
|
+
}
|
|
217
|
+
// 如果没有提供转换函数,回退到返回data
|
|
218
|
+
return response.data;
|
|
219
|
+
case 'data':
|
|
220
|
+
default:
|
|
221
|
+
// 默认只返回data(保持向后兼容)
|
|
222
|
+
return response.data;
|
|
223
|
+
}
|
|
195
224
|
}
|
|
196
225
|
catch (error) {
|
|
197
226
|
// 错误日志
|
|
@@ -265,58 +294,30 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
265
294
|
getName() {
|
|
266
295
|
return this.clientName;
|
|
267
296
|
}
|
|
268
|
-
/**
|
|
269
|
-
* Capture calling context information
|
|
270
|
-
* @returns Calling context with service class and method name
|
|
271
|
-
*/
|
|
272
|
-
captureCallingContext() {
|
|
273
|
-
try {
|
|
274
|
-
// Use CallStackExtractor to get the calling context
|
|
275
|
-
const stackInfo = call_stack_extractor_util_1.CallStackExtractor.getCallInfo();
|
|
276
|
-
// Skip internal HTTP client calls
|
|
277
|
-
if (stackInfo.serviceClass && stackInfo.methodName) {
|
|
278
|
-
// Check if it's an internal call
|
|
279
|
-
const isInternal = call_stack_extractor_util_1.CallStackExtractor['isInternalCall'](stackInfo.serviceClass);
|
|
280
|
-
if (!isInternal) {
|
|
281
|
-
return {
|
|
282
|
-
serviceClass: stackInfo.serviceClass,
|
|
283
|
-
methodName: stackInfo.methodName,
|
|
284
|
-
operationName: stackInfo.operationName,
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
// If no useful context found, return empty
|
|
289
|
-
return {};
|
|
290
|
-
}
|
|
291
|
-
catch (error) {
|
|
292
|
-
this.logger.warn('Failed to capture calling context:', error.message);
|
|
293
|
-
return {};
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
297
|
// 便捷方法
|
|
297
|
-
get(url, config, clientName) {
|
|
298
|
+
get(url, config, clientName, returnOptions) {
|
|
298
299
|
return __awaiter(this, void 0, void 0, function* () {
|
|
299
|
-
return this.request(Object.assign(Object.assign({}, config), { method: 'GET', url }), undefined, clientName);
|
|
300
|
+
return this.request(Object.assign(Object.assign({}, config), { method: 'GET', url }), undefined, clientName, returnOptions);
|
|
300
301
|
});
|
|
301
302
|
}
|
|
302
|
-
post(url, data, config, clientName) {
|
|
303
|
+
post(url, data, config, clientName, returnOptions) {
|
|
303
304
|
return __awaiter(this, void 0, void 0, function* () {
|
|
304
|
-
return this.request(Object.assign(Object.assign({}, config), { method: 'POST', url, data }), undefined, clientName);
|
|
305
|
+
return this.request(Object.assign(Object.assign({}, config), { method: 'POST', url, data }), undefined, clientName, returnOptions);
|
|
305
306
|
});
|
|
306
307
|
}
|
|
307
|
-
put(url, data, config, clientName) {
|
|
308
|
+
put(url, data, config, clientName, returnOptions) {
|
|
308
309
|
return __awaiter(this, void 0, void 0, function* () {
|
|
309
|
-
return this.request(Object.assign(Object.assign({}, config), { method: 'PUT', url, data }), undefined, clientName);
|
|
310
|
+
return this.request(Object.assign(Object.assign({}, config), { method: 'PUT', url, data }), undefined, clientName, returnOptions);
|
|
310
311
|
});
|
|
311
312
|
}
|
|
312
|
-
patch(url, data, config, clientName) {
|
|
313
|
+
patch(url, data, config, clientName, returnOptions) {
|
|
313
314
|
return __awaiter(this, void 0, void 0, function* () {
|
|
314
|
-
return this.request(Object.assign(Object.assign({}, config), { method: 'PATCH', url, data }), undefined, clientName);
|
|
315
|
+
return this.request(Object.assign(Object.assign({}, config), { method: 'PATCH', url, data }), undefined, clientName, returnOptions);
|
|
315
316
|
});
|
|
316
317
|
}
|
|
317
|
-
delete(url, config, clientName) {
|
|
318
|
+
delete(url, config, clientName, returnOptions) {
|
|
318
319
|
return __awaiter(this, void 0, void 0, function* () {
|
|
319
|
-
return this.request(Object.assign(Object.assign({}, config), { method: 'DELETE', url }), undefined, clientName);
|
|
320
|
+
return this.request(Object.assign(Object.assign({}, config), { method: 'DELETE', url }), undefined, clientName, returnOptions);
|
|
320
321
|
});
|
|
321
322
|
}
|
|
322
323
|
/**
|
|
@@ -328,12 +329,12 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
328
329
|
* @param options 等待锁选项
|
|
329
330
|
* @returns 响应数据
|
|
330
331
|
*/
|
|
331
|
-
authRequest(config, tokenProvider, options, clientName) {
|
|
332
|
+
authRequest(config, tokenProvider, options, clientName, returnOptions) {
|
|
332
333
|
return __awaiter(this, void 0, void 0, function* () {
|
|
333
334
|
const effectiveClientName = clientName || this.clientName;
|
|
334
335
|
if (!this.redisLockService) {
|
|
335
336
|
this.logger.warn('RedisLockService not available, proceeding without lock');
|
|
336
|
-
return this.request(config, undefined, effectiveClientName);
|
|
337
|
+
return this.request(config, undefined, effectiveClientName, returnOptions);
|
|
337
338
|
}
|
|
338
339
|
const { lockKey = `auth-request:${(0, request_id_util_1.generateRequestId)()}`, lockTimeout = 30000, waitTimeout = 60000, enableRetry = true, } = options || {};
|
|
339
340
|
try {
|
|
@@ -344,7 +345,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
344
345
|
// 添加认证头
|
|
345
346
|
const authConfig = Object.assign(Object.assign({}, config), { headers: Object.assign(Object.assign({}, config.headers), { Authorization: `Bearer ${token}` }) });
|
|
346
347
|
// 执行请求
|
|
347
|
-
return this.request(authConfig, undefined, effectiveClientName);
|
|
348
|
+
return this.request(authConfig, undefined, effectiveClientName, returnOptions);
|
|
348
349
|
}), {
|
|
349
350
|
ttl: lockTimeout,
|
|
350
351
|
retryCount: enableRetry ? 3 : 0,
|
|
@@ -466,6 +467,34 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
466
467
|
}
|
|
467
468
|
});
|
|
468
469
|
}
|
|
470
|
+
/**
|
|
471
|
+
* Capture calling context information
|
|
472
|
+
* @returns Calling context with service class and method name
|
|
473
|
+
*/
|
|
474
|
+
captureCallingContext() {
|
|
475
|
+
try {
|
|
476
|
+
// Use CallStackExtractor to get the calling context
|
|
477
|
+
const stackInfo = call_stack_extractor_util_1.CallStackExtractor.getCallInfo();
|
|
478
|
+
// Skip internal HTTP client calls
|
|
479
|
+
if (stackInfo.serviceClass && stackInfo.methodName) {
|
|
480
|
+
// Check if it's an internal call
|
|
481
|
+
const isInternal = call_stack_extractor_util_1.CallStackExtractor['isInternalCall'](stackInfo.serviceClass);
|
|
482
|
+
if (!isInternal) {
|
|
483
|
+
return {
|
|
484
|
+
serviceClass: stackInfo.serviceClass,
|
|
485
|
+
methodName: stackInfo.methodName,
|
|
486
|
+
operationName: stackInfo.operationName,
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
// If no useful context found, return empty
|
|
491
|
+
return {};
|
|
492
|
+
}
|
|
493
|
+
catch (error) {
|
|
494
|
+
this.logger.warn('Failed to capture calling context:', error.message);
|
|
495
|
+
return {};
|
|
496
|
+
}
|
|
497
|
+
}
|
|
469
498
|
/**
|
|
470
499
|
* 创建Axios实例并配置axios-retry
|
|
471
500
|
*/
|
|
@@ -687,7 +716,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
687
716
|
logHeaders: true,
|
|
688
717
|
logBody: true,
|
|
689
718
|
maxBodyLength: 1000,
|
|
690
|
-
|
|
719
|
+
sanitize: ['password', 'secret', 'token', 'apiKey', 'authorization', 'cookie'],
|
|
691
720
|
logLevel: 'info',
|
|
692
721
|
databaseLogging: {
|
|
693
722
|
enabled: true,
|
|
@@ -33,7 +33,7 @@ export declare class HttpLoggingService implements OnModuleDestroy {
|
|
|
33
33
|
private isProcessing;
|
|
34
34
|
constructor();
|
|
35
35
|
onModuleDestroy(): void;
|
|
36
|
-
initRepository(dataSource: string, tableName: string): Repository<HttpLogEntity
|
|
36
|
+
initRepository(dataSource: string, tableName: string): Repository<HttpLogEntity> | null;
|
|
37
37
|
/**
|
|
38
38
|
* 记录请求开始
|
|
39
39
|
*/
|
|
@@ -77,6 +77,22 @@ export declare class HttpLoggingService implements OnModuleDestroy {
|
|
|
77
77
|
endDate?: Date;
|
|
78
78
|
userId?: string;
|
|
79
79
|
}): Promise<any>;
|
|
80
|
+
/**
|
|
81
|
+
* 获取日志队列统计信息
|
|
82
|
+
*/
|
|
83
|
+
getQueueStats(): {
|
|
84
|
+
queueSize: number;
|
|
85
|
+
isProcessing: boolean;
|
|
86
|
+
config: AsyncLogConfig;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* 手动刷新日志队列
|
|
90
|
+
*/
|
|
91
|
+
manualFlush(): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* 设置异步日志配置
|
|
94
|
+
*/
|
|
95
|
+
setAsyncConfig(config: Partial<AsyncLogConfig>): void;
|
|
80
96
|
/**
|
|
81
97
|
* 提取调用信息
|
|
82
98
|
*/
|
|
@@ -103,38 +119,6 @@ export declare class HttpLoggingService implements OnModuleDestroy {
|
|
|
103
119
|
* 同步保存日志到数据库(用于异步模式内部)
|
|
104
120
|
*/
|
|
105
121
|
private saveLogToDatabase;
|
|
106
|
-
/**
|
|
107
|
-
* 获取日志队列统计信息
|
|
108
|
-
*/
|
|
109
|
-
getQueueStats(): {
|
|
110
|
-
queueSize: number;
|
|
111
|
-
isProcessing: boolean;
|
|
112
|
-
config: AsyncLogConfig;
|
|
113
|
-
};
|
|
114
|
-
/**
|
|
115
|
-
* 手动刷新日志队列
|
|
116
|
-
*/
|
|
117
|
-
manualFlush(): Promise<void>;
|
|
118
|
-
/**
|
|
119
|
-
* 设置异步日志配置
|
|
120
|
-
*/
|
|
121
|
-
setAsyncConfig(config: Partial<AsyncLogConfig>): void;
|
|
122
|
-
/**
|
|
123
|
-
* 转换请求体为字符串
|
|
124
|
-
*/
|
|
125
|
-
private sanitizeBodyAsString;
|
|
126
|
-
/**
|
|
127
|
-
* 清理敏感头信息
|
|
128
|
-
*/
|
|
129
|
-
private sanitizeHeaders;
|
|
130
|
-
/**
|
|
131
|
-
* 清理敏感请求体信息
|
|
132
|
-
*/
|
|
133
|
-
private sanitizeBody;
|
|
134
|
-
/**
|
|
135
|
-
* 递归清理对象中的敏感字段
|
|
136
|
-
*/
|
|
137
|
-
private sanitizeObject;
|
|
138
122
|
/**
|
|
139
123
|
* 获取完整URL
|
|
140
124
|
* @param config Axios请求配置
|