@nest-omni/core 4.1.3-19 → 4.1.3-20
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.module.d.ts +0 -6
- package/cache/cache.module.js +7 -7
- package/cache/cache.service.js +12 -0
- package/cache/dependencies/db.dependency.d.ts +0 -13
- package/cache/dependencies/db.dependency.js +0 -16
- package/cache/dependencies/tag.dependency.d.ts +39 -4
- package/cache/dependencies/tag.dependency.js +109 -11
- package/cache/interfaces/cache-options.interface.d.ts +8 -0
- package/cache/providers/memory-cache.provider.d.ts +20 -0
- package/cache/providers/memory-cache.provider.js +40 -0
- package/http-client/config/http-client.config.d.ts +5 -0
- package/http-client/config/http-client.config.js +24 -13
- package/http-client/decorators/http-client.decorators.d.ts +1 -25
- package/http-client/decorators/http-client.decorators.js +97 -90
- package/http-client/entities/http-log.entity.d.ts +0 -20
- package/http-client/entities/http-log.entity.js +0 -12
- package/http-client/examples/advanced-usage.example.d.ts +4 -5
- package/http-client/examples/advanced-usage.example.js +4 -56
- package/http-client/http-client.module.d.ts +35 -2
- package/http-client/http-client.module.js +80 -75
- package/http-client/index.d.ts +1 -1
- package/http-client/interfaces/api-client-config.interface.d.ts +1 -91
- package/http-client/interfaces/http-client-config.interface.d.ts +53 -62
- package/http-client/services/api-client-registry.service.d.ts +5 -23
- package/http-client/services/api-client-registry.service.js +41 -284
- package/http-client/services/circuit-breaker.service.d.ts +69 -2
- package/http-client/services/circuit-breaker.service.js +185 -7
- package/http-client/services/http-client.service.d.ts +58 -23
- package/http-client/services/http-client.service.js +294 -150
- package/http-client/services/http-log-query.service.js +0 -13
- package/http-client/services/index.d.ts +0 -1
- package/http-client/services/index.js +0 -1
- package/http-client/services/logging.service.d.ts +79 -10
- package/http-client/services/logging.service.js +246 -51
- package/http-client/utils/call-stack-extractor.util.d.ts +26 -0
- package/http-client/utils/call-stack-extractor.util.js +35 -0
- package/http-client/utils/security-validator.util.d.ts +118 -0
- package/http-client/utils/security-validator.util.js +352 -0
- package/package.json +1 -1
- package/redis-lock/lock-heartbeat.service.d.ts +2 -0
- package/redis-lock/lock-heartbeat.service.js +12 -2
- package/redis-lock/redis-lock.service.d.ts +4 -0
- package/redis-lock/redis-lock.service.js +61 -8
- package/http-client/services/cache.service.d.ts +0 -76
- package/http-client/services/cache.service.js +0 -333
|
@@ -21,49 +21,73 @@ const common_1 = require("@nestjs/common");
|
|
|
21
21
|
const config_1 = require("@nestjs/config");
|
|
22
22
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
23
23
|
const typeorm_2 = require("typeorm");
|
|
24
|
-
const cache_service_1 = require("../cache/cache.service");
|
|
25
24
|
const http_client_service_1 = require("./services/http-client.service");
|
|
26
25
|
const circuit_breaker_service_1 = require("./services/circuit-breaker.service");
|
|
27
26
|
const logging_service_1 = require("./services/logging.service");
|
|
28
|
-
const cache_service_2 = require("./services/cache.service");
|
|
29
27
|
const http_log_query_service_1 = require("./services/http-log-query.service");
|
|
30
28
|
const log_cleanup_service_1 = require("./services/log-cleanup.service");
|
|
31
29
|
const api_client_registry_service_1 = require("./services/api-client-registry.service");
|
|
32
30
|
const entities_1 = require("./entities");
|
|
33
|
-
const cache_options_interface_1 = require("../cache/interfaces/cache-options.interface");
|
|
34
31
|
const redis_lock_service_1 = require("../redis-lock/redis-lock.service");
|
|
32
|
+
const http_client_config_1 = require("./config/http-client.config");
|
|
35
33
|
/**
|
|
36
34
|
* HTTP客户端模块
|
|
37
35
|
* 类似Spring Boot的自动配置机制,集成现有的cache服务
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* // 最简单的方式 - 使用所有默认配置
|
|
39
|
+
* HttpClientModule.forRoot()
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* // 只覆盖部分配置
|
|
43
|
+
* HttpClientModule.forRoot({
|
|
44
|
+
* baseURL: 'https://api.example.com',
|
|
45
|
+
* timeout: 5000,
|
|
46
|
+
* })
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // 深度合并配置
|
|
50
|
+
* HttpClientModule.forRoot({
|
|
51
|
+
* logging: {
|
|
52
|
+
* logLevel: 'debug',
|
|
53
|
+
* // 其他 logging 配置会使用默认值
|
|
54
|
+
* },
|
|
55
|
+
* })
|
|
38
56
|
*/
|
|
39
57
|
let HttpClientModule = HttpClientModule_1 = class HttpClientModule {
|
|
40
58
|
/**
|
|
41
59
|
* 动态注册HTTP客户端模块
|
|
60
|
+
* @param config 用户配置,所有字段都是可选的
|
|
61
|
+
* @returns DynamicModule
|
|
42
62
|
*/
|
|
43
63
|
static forRoot(config = {}) {
|
|
44
|
-
var _a, _b;
|
|
45
64
|
// 基础服务提供者
|
|
46
65
|
const baseProviders = [
|
|
47
66
|
{
|
|
48
67
|
provide: 'HTTP_CLIENT_CONFIG',
|
|
49
|
-
useFactory: (configService
|
|
68
|
+
useFactory: (configService) => {
|
|
69
|
+
// 1. 获取环境配置
|
|
50
70
|
const envConfig = this.loadConfigFromEnvironment(configService);
|
|
51
|
-
|
|
71
|
+
// 2. 根据环境获取基础默认配置
|
|
72
|
+
const nodeEnv = configService.get('NODE_ENV', 'development');
|
|
73
|
+
const environmentDefaults = (0, http_client_config_1.getHttpClientConfig)(nodeEnv);
|
|
74
|
+
// 3. 深度合并: 环境默认值 -> 环境变量配置 -> 用户配置
|
|
75
|
+
// 用户配置优先级最高,会覆盖前面的配置
|
|
76
|
+
return (0, http_client_config_1.mergeHttpClientConfig)((0, http_client_config_1.mergeHttpClientConfig)(envConfig, environmentDefaults), config);
|
|
52
77
|
},
|
|
53
|
-
inject: [config_1.ConfigService
|
|
78
|
+
inject: [config_1.ConfigService],
|
|
54
79
|
},
|
|
55
80
|
circuit_breaker_service_1.HttpCircuitBreakerService,
|
|
56
81
|
{
|
|
57
82
|
provide: logging_service_1.HttpLoggingService,
|
|
58
|
-
useFactory: (httpConfig
|
|
83
|
+
useFactory: (httpConfig) => {
|
|
59
84
|
var _a, _b;
|
|
60
85
|
// Check if database logging is enabled in the config
|
|
61
86
|
const databaseLoggingEnabled = (_b = (_a = httpConfig === null || httpConfig === void 0 ? void 0 : httpConfig.logging) === null || _a === void 0 ? void 0 : _a.databaseLogging) === null || _b === void 0 ? void 0 : _b.enabled;
|
|
62
|
-
return new logging_service_1.HttpLoggingService(
|
|
87
|
+
return new logging_service_1.HttpLoggingService();
|
|
63
88
|
},
|
|
64
89
|
inject: ['HTTP_CLIENT_CONFIG', typeorm_2.DataSource],
|
|
65
90
|
},
|
|
66
|
-
cache_service_2.HttpCacheService,
|
|
67
91
|
http_log_query_service_1.HttpLogQueryService,
|
|
68
92
|
{
|
|
69
93
|
provide: log_cleanup_service_1.HttpLogCleanupService,
|
|
@@ -74,26 +98,23 @@ let HttpClientModule = HttpClientModule_1 = class HttpClientModule {
|
|
|
74
98
|
},
|
|
75
99
|
{
|
|
76
100
|
provide: api_client_registry_service_1.ApiClientRegistryService,
|
|
77
|
-
useFactory: (
|
|
78
|
-
return new api_client_registry_service_1.ApiClientRegistryService(
|
|
101
|
+
useFactory: (circuitBreakerService, loggingService, httpConfig) => {
|
|
102
|
+
return new api_client_registry_service_1.ApiClientRegistryService(circuitBreakerService, loggingService, {});
|
|
79
103
|
},
|
|
80
104
|
inject: [
|
|
81
|
-
http_client_service_1.HttpClientService,
|
|
82
105
|
circuit_breaker_service_1.HttpCircuitBreakerService,
|
|
83
106
|
logging_service_1.HttpLoggingService,
|
|
84
|
-
cache_service_2.HttpCacheService,
|
|
85
107
|
'HTTP_CLIENT_CONFIG',
|
|
86
108
|
],
|
|
87
109
|
},
|
|
88
110
|
{
|
|
89
111
|
provide: http_client_service_1.HttpClientService,
|
|
90
|
-
useFactory: (circuitBreakerService, loggingService,
|
|
91
|
-
return new http_client_service_1.HttpClientService(circuitBreakerService, loggingService,
|
|
112
|
+
useFactory: (circuitBreakerService, loggingService, redisLockService, httpConfig) => {
|
|
113
|
+
return new http_client_service_1.HttpClientService(circuitBreakerService, loggingService, redisLockService, httpConfig);
|
|
92
114
|
},
|
|
93
115
|
inject: [
|
|
94
116
|
circuit_breaker_service_1.HttpCircuitBreakerService,
|
|
95
117
|
logging_service_1.HttpLoggingService,
|
|
96
|
-
cache_service_2.HttpCacheService,
|
|
97
118
|
redis_lock_service_1.RedisLockService,
|
|
98
119
|
'HTTP_CLIENT_CONFIG',
|
|
99
120
|
],
|
|
@@ -104,16 +125,16 @@ let HttpClientModule = HttpClientModule_1 = class HttpClientModule {
|
|
|
104
125
|
http_client_service_1.HttpClientService,
|
|
105
126
|
circuit_breaker_service_1.HttpCircuitBreakerService,
|
|
106
127
|
logging_service_1.HttpLoggingService,
|
|
107
|
-
cache_service_2.HttpCacheService,
|
|
108
128
|
http_log_query_service_1.HttpLogQueryService,
|
|
109
129
|
log_cleanup_service_1.HttpLogCleanupService,
|
|
110
130
|
api_client_registry_service_1.ApiClientRegistryService,
|
|
111
131
|
];
|
|
112
|
-
// 动态导入
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
132
|
+
// 动态导入 - 需要根据最终配置判断
|
|
133
|
+
// 由于配置是在运行时确定的,我们使用条件导入
|
|
134
|
+
const dynamicImports = [
|
|
135
|
+
config_1.ConfigModule,
|
|
136
|
+
typeorm_1.TypeOrmModule.forFeature([entities_1.HttpLogEntity]), // 始终导入,服务内部根据配置决定是否使用
|
|
137
|
+
];
|
|
117
138
|
return {
|
|
118
139
|
module: HttpClientModule_1,
|
|
119
140
|
imports: dynamicImports,
|
|
@@ -123,35 +144,50 @@ let HttpClientModule = HttpClientModule_1 = class HttpClientModule {
|
|
|
123
144
|
}
|
|
124
145
|
/**
|
|
125
146
|
* 异步注册HTTP客户端模块
|
|
147
|
+
* @param config 异步配置,所有字段都是可选的
|
|
148
|
+
* @returns DynamicModule
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* HttpClientModule.forRootAsync({
|
|
152
|
+
* useFactory: (configService: ConfigService) => ({
|
|
153
|
+
* baseURL: configService.get('API_BASE_URL'),
|
|
154
|
+
* timeout: 5000,
|
|
155
|
+
* }),
|
|
156
|
+
* inject: [ConfigService],
|
|
157
|
+
* })
|
|
126
158
|
*/
|
|
127
159
|
static forRootAsync(config) {
|
|
128
|
-
// Determine if database logging will be enabled
|
|
129
|
-
// We need to check if the config will enable database logging
|
|
130
|
-
// This is a bit tricky since the config is async, so we'll inject DataSource conditionally later
|
|
131
|
-
const httpConfig = config.useFactory ? {} : {};
|
|
132
160
|
// 基础服务提供者
|
|
133
161
|
const baseProviders = [
|
|
134
162
|
{
|
|
135
163
|
provide: 'HTTP_CLIENT_CONFIG',
|
|
136
164
|
useFactory: (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
165
|
+
// 1. 获取用户配置
|
|
137
166
|
const userConfig = yield config.useFactory(...args);
|
|
138
|
-
|
|
139
|
-
|
|
167
|
+
// 2. 获取环境配置
|
|
168
|
+
const configService = args[0];
|
|
169
|
+
const envConfig = this.loadConfigFromEnvironment(configService);
|
|
170
|
+
// 3. 根据环境获取基础默认配置
|
|
171
|
+
const nodeEnv = configService.get('NODE_ENV', 'development');
|
|
172
|
+
const environmentDefaults = (0, http_client_config_1.getHttpClientConfig)(nodeEnv);
|
|
173
|
+
// 4. 深度合并: 环境默认值 -> 环境变量配置 -> 用户配置
|
|
174
|
+
// 用户配置优先级最高,会覆盖前面的配置
|
|
175
|
+
const finalConfig = (0, http_client_config_1.mergeHttpClientConfig)((0, http_client_config_1.mergeHttpClientConfig)(envConfig, environmentDefaults), userConfig);
|
|
176
|
+
return finalConfig;
|
|
140
177
|
}),
|
|
141
178
|
inject: config.inject || [config_1.ConfigService],
|
|
142
179
|
},
|
|
143
180
|
circuit_breaker_service_1.HttpCircuitBreakerService,
|
|
144
181
|
{
|
|
145
182
|
provide: logging_service_1.HttpLoggingService,
|
|
146
|
-
useFactory: (httpConfig
|
|
183
|
+
useFactory: (httpConfig) => {
|
|
147
184
|
var _a, _b;
|
|
148
185
|
// Check if database logging is enabled in the config
|
|
149
186
|
const databaseLoggingEnabled = (_b = (_a = httpConfig === null || httpConfig === void 0 ? void 0 : httpConfig.logging) === null || _a === void 0 ? void 0 : _a.databaseLogging) === null || _b === void 0 ? void 0 : _b.enabled;
|
|
150
|
-
return new logging_service_1.HttpLoggingService(
|
|
187
|
+
return new logging_service_1.HttpLoggingService();
|
|
151
188
|
},
|
|
152
189
|
inject: ['HTTP_CLIENT_CONFIG', typeorm_2.DataSource],
|
|
153
190
|
},
|
|
154
|
-
cache_service_2.HttpCacheService,
|
|
155
191
|
http_log_query_service_1.HttpLogQueryService,
|
|
156
192
|
{
|
|
157
193
|
provide: log_cleanup_service_1.HttpLogCleanupService,
|
|
@@ -162,26 +198,23 @@ let HttpClientModule = HttpClientModule_1 = class HttpClientModule {
|
|
|
162
198
|
},
|
|
163
199
|
{
|
|
164
200
|
provide: api_client_registry_service_1.ApiClientRegistryService,
|
|
165
|
-
useFactory: (
|
|
166
|
-
return new api_client_registry_service_1.ApiClientRegistryService(
|
|
201
|
+
useFactory: (circuitBreakerService, loggingService, httpConfig) => {
|
|
202
|
+
return new api_client_registry_service_1.ApiClientRegistryService(circuitBreakerService, loggingService, {});
|
|
167
203
|
},
|
|
168
204
|
inject: [
|
|
169
|
-
http_client_service_1.HttpClientService,
|
|
170
205
|
circuit_breaker_service_1.HttpCircuitBreakerService,
|
|
171
206
|
logging_service_1.HttpLoggingService,
|
|
172
|
-
cache_service_2.HttpCacheService,
|
|
173
207
|
'HTTP_CLIENT_CONFIG',
|
|
174
208
|
],
|
|
175
209
|
},
|
|
176
210
|
{
|
|
177
211
|
provide: http_client_service_1.HttpClientService,
|
|
178
|
-
useFactory: (circuitBreakerService, loggingService,
|
|
179
|
-
return new http_client_service_1.HttpClientService(circuitBreakerService, loggingService,
|
|
212
|
+
useFactory: (circuitBreakerService, loggingService, redisLockService, httpConfig) => {
|
|
213
|
+
return new http_client_service_1.HttpClientService(circuitBreakerService, loggingService, redisLockService, httpConfig);
|
|
180
214
|
},
|
|
181
215
|
inject: [
|
|
182
216
|
circuit_breaker_service_1.HttpCircuitBreakerService,
|
|
183
217
|
logging_service_1.HttpLoggingService,
|
|
184
|
-
cache_service_2.HttpCacheService,
|
|
185
218
|
redis_lock_service_1.RedisLockService,
|
|
186
219
|
'HTTP_CLIENT_CONFIG',
|
|
187
220
|
],
|
|
@@ -192,13 +225,16 @@ let HttpClientModule = HttpClientModule_1 = class HttpClientModule {
|
|
|
192
225
|
http_client_service_1.HttpClientService,
|
|
193
226
|
circuit_breaker_service_1.HttpCircuitBreakerService,
|
|
194
227
|
logging_service_1.HttpLoggingService,
|
|
195
|
-
cache_service_2.HttpCacheService,
|
|
196
228
|
http_log_query_service_1.HttpLogQueryService,
|
|
197
229
|
log_cleanup_service_1.HttpLogCleanupService,
|
|
198
230
|
api_client_registry_service_1.ApiClientRegistryService,
|
|
199
231
|
];
|
|
200
232
|
// 动态导入
|
|
201
|
-
const dynamicImports = [
|
|
233
|
+
const dynamicImports = [
|
|
234
|
+
config_1.ConfigModule,
|
|
235
|
+
typeorm_1.TypeOrmModule.forFeature([entities_1.HttpLogEntity]), // 始终导入,服务内部根据配置决定是否使用
|
|
236
|
+
...(config.imports || []),
|
|
237
|
+
];
|
|
202
238
|
return {
|
|
203
239
|
module: HttpClientModule_1,
|
|
204
240
|
imports: dynamicImports,
|
|
@@ -210,7 +246,7 @@ let HttpClientModule = HttpClientModule_1 = class HttpClientModule {
|
|
|
210
246
|
* 从环境变量加载配置
|
|
211
247
|
*/
|
|
212
248
|
static loadConfigFromEnvironment(configService) {
|
|
213
|
-
var _a
|
|
249
|
+
var _a;
|
|
214
250
|
return {
|
|
215
251
|
baseURL: configService.get('HTTP_CLIENT_BASE_URL'),
|
|
216
252
|
timeout: configService.get('HTTP_CLIENT_TIMEOUT')
|
|
@@ -249,35 +285,6 @@ let HttpClientModule = HttpClientModule_1 = class HttpClientModule {
|
|
|
249
285
|
: 10,
|
|
250
286
|
countHalfOpenCalls: configService.get('HTTP_CLIENT_CIRCUIT_BREAKER_COUNT_HALF_OPEN') === 'true',
|
|
251
287
|
},
|
|
252
|
-
cache: {
|
|
253
|
-
enabled: configService.get('HTTP_CLIENT_CACHE_ENABLED') !== 'false',
|
|
254
|
-
defaultTtl: configService.get('HTTP_CLIENT_CACHE_DEFAULT_TTL')
|
|
255
|
-
? parseInt(configService.get('HTTP_CLIENT_CACHE_DEFAULT_TTL'))
|
|
256
|
-
: 300000,
|
|
257
|
-
cacheableMethods: ((_b = (_a = configService
|
|
258
|
-
.get('HTTP_CLIENT_CACHEABLE_METHODS')) === null || _a === void 0 ? void 0 : _a.split(',')) === null || _b === void 0 ? void 0 : _b.map((method) => method.trim().toUpperCase())) || [
|
|
259
|
-
'GET',
|
|
260
|
-
'HEAD',
|
|
261
|
-
],
|
|
262
|
-
cacheableStatusCodes: ((_d = (_c = configService
|
|
263
|
-
.get('HTTP_CLIENT_CACHEABLE_STATUS_CODES')) === null || _c === void 0 ? void 0 : _c.split(',')) === null || _d === void 0 ? void 0 : _d.map((code) => parseInt(code.trim()))) || [200, 201, 304],
|
|
264
|
-
options: {
|
|
265
|
-
layers: ((_f = (_e = configService
|
|
266
|
-
.get('HTTP_CLIENT_CACHE_LAYERS')) === null || _e === void 0 ? void 0 : _e.split(',')) === null || _f === void 0 ? void 0 : _f.map((layer) => {
|
|
267
|
-
const trimmed = layer.trim();
|
|
268
|
-
switch (trimmed) {
|
|
269
|
-
case 'cls':
|
|
270
|
-
return cache_options_interface_1.CacheLayer.CLS;
|
|
271
|
-
case 'memory':
|
|
272
|
-
return cache_options_interface_1.CacheLayer.MEMORY;
|
|
273
|
-
case 'redis':
|
|
274
|
-
return cache_options_interface_1.CacheLayer.REDIS;
|
|
275
|
-
default:
|
|
276
|
-
return cache_options_interface_1.CacheLayer.MEMORY;
|
|
277
|
-
}
|
|
278
|
-
})) || [cache_options_interface_1.CacheLayer.MEMORY],
|
|
279
|
-
},
|
|
280
|
-
},
|
|
281
288
|
logging: {
|
|
282
289
|
enabled: configService.get('HTTP_CLIENT_LOGGING_ENABLED') !== 'false',
|
|
283
290
|
logRequests: configService.get('HTTP_CLIENT_LOG_REQUESTS') !== 'false',
|
|
@@ -288,16 +295,14 @@ let HttpClientModule = HttpClientModule_1 = class HttpClientModule {
|
|
|
288
295
|
maxBodyLength: configService.get('HTTP_CLIENT_LOG_MAX_BODY_LENGTH')
|
|
289
296
|
? parseInt(configService.get('HTTP_CLIENT_LOG_MAX_BODY_LENGTH'))
|
|
290
297
|
: undefined,
|
|
291
|
-
sanitizeHeaders: (
|
|
292
|
-
.get('HTTP_CLIENT_LOG_SANITIZE_HEADERS')) === null ||
|
|
298
|
+
sanitizeHeaders: (_a = configService
|
|
299
|
+
.get('HTTP_CLIENT_LOG_SANITIZE_HEADERS')) === null || _a === void 0 ? void 0 : _a.split(','),
|
|
293
300
|
logLevel: configService.get('HTTP_CLIENT_LOG_LEVEL'),
|
|
294
301
|
databaseLogging: {
|
|
295
302
|
enabled: configService.get('HTTP_CLIENT_DB_LOGGING_ENABLED') ===
|
|
296
303
|
'true',
|
|
297
304
|
dataSource: configService.get('HTTP_CLIENT_DB_LOGGING_DATA_SOURCE') ||
|
|
298
305
|
'default',
|
|
299
|
-
tableName: configService.get('HTTP_CLIENT_DB_LOGGING_TABLE_NAME') ||
|
|
300
|
-
'http_logs',
|
|
301
306
|
},
|
|
302
307
|
},
|
|
303
308
|
proxy: {
|
package/http-client/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { HttpClientConfig, RetryConfig, CircuitBreakerConfig,
|
|
1
|
+
export { HttpClientConfig, 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';
|
|
@@ -47,6 +47,7 @@ export interface OAuth2Config {
|
|
|
47
47
|
password?: string;
|
|
48
48
|
redirectUri?: string;
|
|
49
49
|
refreshToken?: string;
|
|
50
|
+
accessToken?: string;
|
|
50
51
|
}
|
|
51
52
|
/**
|
|
52
53
|
* 自定义鉴权配置
|
|
@@ -184,94 +185,3 @@ export interface ApiClientRegistryConfig {
|
|
|
184
185
|
/** 是否启用熔断器 */
|
|
185
186
|
enableCircuitBreaker?: boolean;
|
|
186
187
|
}
|
|
187
|
-
/**
|
|
188
|
-
* API客户端工厂接口
|
|
189
|
-
*/
|
|
190
|
-
export interface ApiClientFactory {
|
|
191
|
-
/**
|
|
192
|
-
* 创建API客户端实例
|
|
193
|
-
*/
|
|
194
|
-
createClient<T = any>(config: ApiClientInstanceConfig): T;
|
|
195
|
-
/**
|
|
196
|
-
* 获取已注册的客户端
|
|
197
|
-
*/
|
|
198
|
-
getClient<T = any>(name: string): T;
|
|
199
|
-
/**
|
|
200
|
-
* 列出所有已注册的客户端
|
|
201
|
-
*/
|
|
202
|
-
listClients(): string[];
|
|
203
|
-
/**
|
|
204
|
-
* 更新客户端配置
|
|
205
|
-
*/
|
|
206
|
-
updateClient(name: string, config: Partial<ApiClientConfig>): void;
|
|
207
|
-
/**
|
|
208
|
-
* 移除客户端
|
|
209
|
-
*/
|
|
210
|
-
removeClient(name: string): void;
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* API客户端接口
|
|
214
|
-
*/
|
|
215
|
-
export interface ApiClient {
|
|
216
|
-
/** 客户端名称 */
|
|
217
|
-
name: string;
|
|
218
|
-
/** 客户端配置 */
|
|
219
|
-
config: ApiClientConfig;
|
|
220
|
-
/** 基础HTTP请求方法 */
|
|
221
|
-
get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
|
|
222
|
-
post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
|
|
223
|
-
put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
|
|
224
|
-
patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
|
|
225
|
-
delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
|
|
226
|
-
/** 通用请求方法 */
|
|
227
|
-
request<T = any>(config: AxiosRequestConfig): Promise<T>;
|
|
228
|
-
/** 获取客户端统计信息 */
|
|
229
|
-
getStats(): any;
|
|
230
|
-
/** 重置统计信息 */
|
|
231
|
-
resetStats(): void;
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* 通用API响应格式
|
|
235
|
-
*/
|
|
236
|
-
export interface ApiResponse<T = any> {
|
|
237
|
-
/** 响应数据 */
|
|
238
|
-
data?: T;
|
|
239
|
-
/** 响应代码 */
|
|
240
|
-
code?: number;
|
|
241
|
-
/** 响应消息 */
|
|
242
|
-
message?: string;
|
|
243
|
-
/** 成功标识 */
|
|
244
|
-
success?: boolean;
|
|
245
|
-
/** 错误详情 */
|
|
246
|
-
error?: {
|
|
247
|
-
code?: string;
|
|
248
|
-
message?: string;
|
|
249
|
-
details?: any;
|
|
250
|
-
};
|
|
251
|
-
/** 分页信息 */
|
|
252
|
-
pagination?: {
|
|
253
|
-
page?: number;
|
|
254
|
-
pageSize?: number;
|
|
255
|
-
total?: number;
|
|
256
|
-
totalPages?: number;
|
|
257
|
-
};
|
|
258
|
-
/** 请求ID */
|
|
259
|
-
requestId?: string;
|
|
260
|
-
/** 时间戳 */
|
|
261
|
-
timestamp?: string;
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* 错误响应格式
|
|
265
|
-
*/
|
|
266
|
-
export interface ErrorResponse {
|
|
267
|
-
/** 错误代码 */
|
|
268
|
-
code: string | number;
|
|
269
|
-
/** 错误消息 */
|
|
270
|
-
message: string;
|
|
271
|
-
/** 错误详情 */
|
|
272
|
-
details?: any;
|
|
273
|
-
/** 堆栈信息 */
|
|
274
|
-
stack?: string;
|
|
275
|
-
/** 请求ID */
|
|
276
|
-
requestId?: string;
|
|
277
|
-
}
|
|
@@ -1,37 +1,46 @@
|
|
|
1
1
|
import { AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
2
|
-
import { CacheOptions } from '../../cache/interfaces/cache-options.interface';
|
|
3
2
|
import { LogCleanupConfig } from '../services/log-cleanup.service';
|
|
3
|
+
import { SSRFProtectionConfig, URLValidationConfig } from '../utils/security-validator.util';
|
|
4
4
|
/**
|
|
5
5
|
* HTTP客户端配置接口
|
|
6
6
|
* 基于Spring Boot的@ConfigurationProperties设计理念
|
|
7
|
+
* 所有字段都是可选的,模块会使用合理的默认值
|
|
7
8
|
*/
|
|
8
9
|
export interface HttpClientConfig {
|
|
9
10
|
/** 基础配置 */
|
|
10
11
|
baseURL?: string;
|
|
11
12
|
timeout?: number;
|
|
12
13
|
/** 重试配置 */
|
|
13
|
-
retry?: RetryConfig
|
|
14
|
+
retry?: Partial<RetryConfig>;
|
|
14
15
|
/** 熔断器配置 */
|
|
15
|
-
circuitBreaker?: CircuitBreakerConfig
|
|
16
|
-
/** 缓存配置 */
|
|
17
|
-
cache?: HttpCacheConfig;
|
|
16
|
+
circuitBreaker?: Partial<CircuitBreakerConfig>;
|
|
18
17
|
/** 代理配置 */
|
|
19
|
-
proxy?: ProxyConfig
|
|
18
|
+
proxy?: Partial<ProxyConfig>;
|
|
20
19
|
/** 日志配置 */
|
|
21
|
-
logging?: LoggingConfig
|
|
20
|
+
logging?: Partial<LoggingConfig>;
|
|
22
21
|
/** 日志清理配置 */
|
|
23
|
-
logCleanup?: LogCleanupConfig
|
|
22
|
+
logCleanup?: Partial<LogCleanupConfig>;
|
|
24
23
|
/** 拦截器配置 */
|
|
25
|
-
interceptors?: InterceptorConfig
|
|
24
|
+
interceptors?: Partial<InterceptorConfig>;
|
|
26
25
|
/** 连接池配置 */
|
|
27
|
-
connectionPool?: ConnectionPoolConfig
|
|
26
|
+
connectionPool?: Partial<ConnectionPoolConfig>;
|
|
27
|
+
/** 安全配置 */
|
|
28
|
+
security?: {
|
|
29
|
+
/** URL验证配置 */
|
|
30
|
+
urlValidation?: Partial<URLValidationConfig>;
|
|
31
|
+
/** SSRF防护配置 */
|
|
32
|
+
ssrfProtection?: Partial<SSRFProtectionConfig>;
|
|
33
|
+
/** 是否启用安全验证 */
|
|
34
|
+
enabled?: boolean;
|
|
35
|
+
};
|
|
28
36
|
}
|
|
29
37
|
/**
|
|
30
38
|
* 重试配置
|
|
31
39
|
* 基于axios-retry库的配置
|
|
40
|
+
* 所有字段都是可选的
|
|
32
41
|
*/
|
|
33
42
|
export interface RetryConfig {
|
|
34
|
-
enabled
|
|
43
|
+
enabled?: boolean;
|
|
35
44
|
retries?: number;
|
|
36
45
|
retryDelay?: (retryCount: number) => number;
|
|
37
46
|
retryCondition?: (error: any) => boolean;
|
|
@@ -41,37 +50,22 @@ export interface RetryConfig {
|
|
|
41
50
|
/**
|
|
42
51
|
* 熔断器配置
|
|
43
52
|
* 类似Spring Cloud CircuitBreaker
|
|
53
|
+
* 所有字段都是可选的
|
|
44
54
|
*/
|
|
45
55
|
export interface CircuitBreakerConfig {
|
|
46
|
-
enabled
|
|
47
|
-
failureThreshold
|
|
48
|
-
recoveryTimeoutMs
|
|
49
|
-
monitoringPeriodMs
|
|
50
|
-
minimumThroughputThreshold
|
|
51
|
-
countHalfOpenCalls
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* HTTP缓存配置
|
|
55
|
-
* 集成现有的三层缓存架构
|
|
56
|
-
*/
|
|
57
|
-
export interface HttpCacheConfig {
|
|
58
|
-
enabled: boolean;
|
|
59
|
-
/** 缓存选项,使用core中的CacheOptions */
|
|
60
|
-
options?: Omit<CacheOptions, 'ttl' | 'namespace'>;
|
|
61
|
-
/** 默认TTL(毫秒) */
|
|
62
|
-
defaultTtl?: number;
|
|
63
|
-
/** 可缓存的方法 */
|
|
64
|
-
cacheableMethods: string[];
|
|
65
|
-
/** 可缓存的状态码 */
|
|
66
|
-
cacheableStatusCodes: number[];
|
|
67
|
-
/** 自定义缓存键生成器 */
|
|
68
|
-
keyGenerator?: (config: AxiosRequestConfig) => string;
|
|
56
|
+
enabled?: boolean;
|
|
57
|
+
failureThreshold?: number;
|
|
58
|
+
recoveryTimeoutMs?: number;
|
|
59
|
+
monitoringPeriodMs?: number;
|
|
60
|
+
minimumThroughputThreshold?: number;
|
|
61
|
+
countHalfOpenCalls?: boolean;
|
|
69
62
|
}
|
|
70
63
|
/**
|
|
71
64
|
* 代理配置
|
|
65
|
+
* 所有字段都是可选的
|
|
72
66
|
*/
|
|
73
67
|
export interface ProxyConfig {
|
|
74
|
-
enabled
|
|
68
|
+
enabled?: boolean;
|
|
75
69
|
/** 是否从环境变量读取代理配置 (HTTP_PROXY, HTTPS_PROXY, NO_PROXY) */
|
|
76
70
|
fromEnvironment?: boolean;
|
|
77
71
|
/** 手动指定的代理主机 (当 fromEnvironment 为 false 时使用) */
|
|
@@ -82,47 +76,49 @@ export interface ProxyConfig {
|
|
|
82
76
|
protocol?: 'http' | 'https';
|
|
83
77
|
/** 代理认证信息 */
|
|
84
78
|
auth?: {
|
|
85
|
-
username
|
|
86
|
-
password
|
|
79
|
+
username?: string;
|
|
80
|
+
password?: string;
|
|
87
81
|
};
|
|
88
82
|
}
|
|
89
83
|
/**
|
|
90
84
|
* 日志配置
|
|
91
85
|
* 类似Spring Boot的logging配置
|
|
86
|
+
* 所有字段都是可选的
|
|
92
87
|
*/
|
|
93
88
|
export interface LoggingConfig {
|
|
94
|
-
enabled
|
|
95
|
-
logRequests
|
|
96
|
-
logResponses
|
|
97
|
-
logErrors
|
|
98
|
-
logHeaders
|
|
99
|
-
logBody
|
|
100
|
-
maxBodyLength
|
|
101
|
-
sanitizeHeaders
|
|
102
|
-
logLevel
|
|
89
|
+
enabled?: boolean;
|
|
90
|
+
logRequests?: boolean;
|
|
91
|
+
logResponses?: boolean;
|
|
92
|
+
logErrors?: boolean;
|
|
93
|
+
logHeaders?: boolean;
|
|
94
|
+
logBody?: boolean;
|
|
95
|
+
maxBodyLength?: number;
|
|
96
|
+
sanitizeHeaders?: string[];
|
|
97
|
+
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
|
103
98
|
databaseLogging?: {
|
|
104
|
-
enabled
|
|
105
|
-
dataSource
|
|
106
|
-
tableName: string;
|
|
99
|
+
enabled?: boolean;
|
|
100
|
+
dataSource?: string;
|
|
107
101
|
};
|
|
108
102
|
}
|
|
109
103
|
/**
|
|
110
104
|
* 拦截器配置
|
|
105
|
+
* 所有字段都是可选的
|
|
111
106
|
*/
|
|
112
107
|
export interface InterceptorConfig {
|
|
113
|
-
requestInterceptors
|
|
114
|
-
responseInterceptors
|
|
115
|
-
errorInterceptors
|
|
108
|
+
requestInterceptors?: string[];
|
|
109
|
+
responseInterceptors?: string[];
|
|
110
|
+
errorInterceptors?: string[];
|
|
116
111
|
}
|
|
117
112
|
/**
|
|
118
113
|
* 连接池配置
|
|
114
|
+
* 所有字段都是可选的
|
|
119
115
|
*/
|
|
120
116
|
export interface ConnectionPoolConfig {
|
|
121
|
-
enabled
|
|
122
|
-
maxSockets
|
|
123
|
-
maxFreeSockets
|
|
124
|
-
timeoutMs
|
|
125
|
-
keepAlive
|
|
117
|
+
enabled?: boolean;
|
|
118
|
+
maxSockets?: number;
|
|
119
|
+
maxFreeSockets?: number;
|
|
120
|
+
timeoutMs?: number;
|
|
121
|
+
keepAlive?: boolean;
|
|
126
122
|
}
|
|
127
123
|
/**
|
|
128
124
|
* HTTP请求上下文
|
|
@@ -181,9 +177,4 @@ export interface HttpStats {
|
|
|
181
177
|
requestsByMethod: Record<HttpMethod, number>;
|
|
182
178
|
requestsByStatus: Record<number, number>;
|
|
183
179
|
circuitBreakerStats: Record<string, any>;
|
|
184
|
-
cacheStats: {
|
|
185
|
-
hits: number;
|
|
186
|
-
misses: number;
|
|
187
|
-
hitRate: number;
|
|
188
|
-
};
|
|
189
180
|
}
|
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
import { ApiClientConfig, ApiClientInstanceConfig, ApiClientRegistryConfig, AuthType,
|
|
2
|
-
import { HttpClientService } from './http-client.service';
|
|
1
|
+
import { ApiClientConfig, ApiClientInstanceConfig, ApiClientRegistryConfig, AuthType, ResponseTransformerConfig } from '../interfaces/api-client-config.interface';
|
|
3
2
|
import { HttpCircuitBreakerService } from './circuit-breaker.service';
|
|
4
3
|
import { HttpLoggingService } from './logging.service';
|
|
5
|
-
|
|
6
|
-
export { ApiClientInstanceConfig, AuthType, OAuth2Config, ResponseTransformerConfig, };
|
|
4
|
+
export { ApiClientInstanceConfig, AuthType, ResponseTransformerConfig, };
|
|
7
5
|
/**
|
|
8
6
|
* API客户端注册服务
|
|
7
|
+
* 负责管理多个 HttpClientService 实例
|
|
9
8
|
*/
|
|
10
9
|
export declare class ApiClientRegistryService {
|
|
11
|
-
private readonly httpClientService;
|
|
12
10
|
private readonly circuitBreakerService;
|
|
13
11
|
private readonly loggingService;
|
|
14
|
-
private readonly cacheService;
|
|
15
12
|
private readonly logger;
|
|
16
13
|
private readonly clients;
|
|
17
14
|
private readonly clientConfigs;
|
|
18
15
|
private readonly globalDefaults;
|
|
19
|
-
constructor(
|
|
16
|
+
constructor(circuitBreakerService: HttpCircuitBreakerService, loggingService: HttpLoggingService, globalConfig?: ApiClientRegistryConfig);
|
|
20
17
|
/**
|
|
21
18
|
* 创建API客户端实例
|
|
19
|
+
* 使用 HttpClientService.createApiClient 静态方法创建
|
|
22
20
|
*/
|
|
23
21
|
createClient<T = any>(config: ApiClientInstanceConfig): T;
|
|
24
22
|
/**
|
|
@@ -75,22 +73,6 @@ export declare class ApiClientRegistryService {
|
|
|
75
73
|
error?: string;
|
|
76
74
|
}>;
|
|
77
75
|
}>;
|
|
78
|
-
/**
|
|
79
|
-
* 创建Axios实例
|
|
80
|
-
*/
|
|
81
|
-
private createAxiosInstance;
|
|
82
|
-
/**
|
|
83
|
-
* 应用鉴权配置
|
|
84
|
-
*/
|
|
85
|
-
private applyAuthentication;
|
|
86
|
-
/**
|
|
87
|
-
* 应用响应转换器
|
|
88
|
-
*/
|
|
89
|
-
private applyResponseTransformer;
|
|
90
|
-
/**
|
|
91
|
-
* 根据路径提取数据
|
|
92
|
-
*/
|
|
93
|
-
private extractDataByPath;
|
|
94
76
|
/**
|
|
95
77
|
* 合并环境特定配置
|
|
96
78
|
*/
|