@nest-omni/core 4.1.3-2 → 4.1.3-4
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/audit/audit.module.d.ts +10 -0
- package/audit/audit.module.js +15 -0
- package/audit/controllers/audit.controller.d.ts +24 -0
- package/audit/controllers/audit.controller.js +24 -0
- package/audit/decorators/audit-controller.decorator.d.ts +8 -0
- package/audit/decorators/audit-controller.decorator.js +9 -0
- package/audit/decorators/audit-operation.decorator.d.ts +45 -0
- package/audit/decorators/audit-operation.decorator.js +49 -0
- package/audit/decorators/entity-audit.decorator.d.ts +8 -0
- package/audit/decorators/entity-audit.decorator.js +9 -0
- package/audit/dto/audit-log-query.dto.d.ts +3 -0
- package/audit/dto/audit-log-query.dto.js +3 -0
- package/audit/dto/begin-transaction.dto.d.ts +3 -0
- package/audit/dto/begin-transaction.dto.js +3 -0
- package/audit/dto/compare-entities.dto.d.ts +3 -0
- package/audit/dto/compare-entities.dto.js +3 -0
- package/audit/dto/pre-check-restore.dto.d.ts +3 -0
- package/audit/dto/pre-check-restore.dto.js +3 -0
- package/audit/dto/restore-entity.dto.d.ts +3 -0
- package/audit/dto/restore-entity.dto.js +3 -0
- package/audit/entities/entity-audit-log.entity.d.ts +3 -0
- package/audit/entities/entity-audit-log.entity.js +3 -0
- package/audit/entities/entity-transaction.entity.d.ts +3 -0
- package/audit/entities/entity-transaction.entity.js +3 -0
- package/audit/entities/manual-operation-log.entity.d.ts +4 -0
- package/audit/entities/manual-operation-log.entity.js +4 -0
- package/audit/entities/operation-template.entity.d.ts +4 -0
- package/audit/entities/operation-template.entity.js +4 -0
- package/audit/enums/audit.enums.d.ts +17 -2
- package/audit/enums/audit.enums.js +15 -0
- package/audit/index.js +10 -0
- package/audit/interceptors/audit.interceptor.d.ts +15 -0
- package/audit/interceptors/audit.interceptor.js +23 -1
- package/audit/interfaces/audit.interfaces.d.ts +42 -0
- package/audit/services/audit-context.service.d.ts +15 -0
- package/audit/services/audit-context.service.js +15 -0
- package/audit/services/audit-strategy.service.d.ts +6 -0
- package/audit/services/audit-strategy.service.js +13 -0
- package/audit/services/entity-audit.service.d.ts +57 -0
- package/audit/services/entity-audit.service.js +91 -0
- package/audit/services/manual-audit-log.service.d.ts +124 -0
- package/audit/services/manual-audit-log.service.js +138 -0
- package/audit/services/multi-database.service.d.ts +12 -0
- package/audit/services/multi-database.service.js +12 -0
- package/audit/services/operation-description.service.d.ts +59 -0
- package/audit/services/operation-description.service.js +76 -2
- package/audit/services/transaction-audit.service.d.ts +30 -0
- package/audit/services/transaction-audit.service.js +47 -0
- package/audit/subscribers/entity-audit.subscriber.d.ts +15 -0
- package/audit/subscribers/entity-audit.subscriber.js +29 -1
- package/cache/cache-metrics.service.d.ts +67 -0
- package/cache/cache-metrics.service.js +68 -4
- package/cache/cache-serialization.service.d.ts +31 -0
- package/cache/cache-serialization.service.js +25 -0
- package/cache/cache.constants.d.ts +9 -0
- package/cache/cache.constants.js +9 -0
- package/cache/cache.health.d.ts +26 -0
- package/cache/cache.health.js +30 -0
- package/cache/cache.module.d.ts +86 -0
- package/cache/cache.module.js +71 -0
- package/cache/cache.service.d.ts +140 -0
- package/cache/cache.service.js +157 -0
- package/cache/cache.warmup.service.d.ts +39 -0
- package/cache/cache.warmup.service.js +32 -0
- package/cache/decorators/cache-evict.decorator.d.ts +47 -0
- package/cache/decorators/cache-evict.decorator.js +56 -0
- package/cache/decorators/cache-put.decorator.d.ts +34 -0
- package/cache/decorators/cache-put.decorator.js +39 -0
- package/cache/decorators/cacheable.decorator.d.ts +40 -0
- package/cache/decorators/cacheable.decorator.js +55 -0
- package/cache/dependencies/callback.dependency.d.ts +33 -0
- package/cache/dependencies/callback.dependency.js +39 -1
- package/cache/dependencies/chain.dependency.d.ts +28 -0
- package/cache/dependencies/chain.dependency.js +34 -0
- package/cache/dependencies/db.dependency.d.ts +45 -0
- package/cache/dependencies/db.dependency.js +48 -1
- package/cache/dependencies/file.dependency.d.ts +32 -0
- package/cache/dependencies/file.dependency.js +34 -0
- package/cache/dependencies/tag.dependency.d.ts +36 -0
- package/cache/dependencies/tag.dependency.js +36 -0
- package/cache/dependencies/time.dependency.d.ts +43 -0
- package/cache/dependencies/time.dependency.js +43 -0
- package/cache/examples/basic-usage.d.ts +15 -0
- package/cache/examples/basic-usage.js +62 -8
- package/cache/index.js +9 -0
- package/cache/interfaces/cache-dependency.interface.d.ts +53 -0
- package/cache/interfaces/cache-options.interface.d.ts +81 -0
- package/cache/interfaces/cache-options.interface.js +6 -0
- package/cache/interfaces/cache-provider.interface.d.ts +78 -0
- package/cache/providers/base-cache.provider.d.ts +14 -0
- package/cache/providers/base-cache.provider.js +16 -0
- package/cache/providers/cls-cache.provider.d.ts +20 -0
- package/cache/providers/cls-cache.provider.js +28 -0
- package/cache/providers/memory-cache.provider.d.ts +23 -0
- package/cache/providers/memory-cache.provider.js +26 -0
- package/cache/providers/redis-cache.provider.d.ts +26 -0
- package/cache/providers/redis-cache.provider.js +29 -0
- package/cache/utils/dependency-manager.util.d.ts +52 -0
- package/cache/utils/dependency-manager.util.js +59 -0
- package/cache/utils/key-generator.util.d.ts +42 -0
- package/cache/utils/key-generator.util.js +53 -1
- package/common/abstract.entity.d.ts +14 -0
- package/common/abstract.entity.js +14 -0
- package/common/boilerplate.polyfill.d.ts +142 -0
- package/common/boilerplate.polyfill.js +17 -0
- package/common/dto/dto-container.d.ts +16 -0
- package/common/dto/dto-container.js +20 -0
- package/common/dto/dto-decorators.d.ts +18 -0
- package/common/dto/dto-decorators.js +14 -0
- package/common/dto/dto-extensions.d.ts +11 -0
- package/common/dto/dto-extensions.js +9 -0
- package/common/dto/dto-service-accessor.d.ts +17 -0
- package/common/dto/dto-service-accessor.js +18 -0
- package/common/dto/dto-transformer.d.ts +12 -0
- package/common/dto/dto-transformer.js +9 -0
- package/common/dto/index.js +2 -0
- package/common/examples/paginate-and-map.example.d.ts +6 -0
- package/common/examples/paginate-and-map.example.js +26 -0
- package/common/utils.d.ts +15 -0
- package/common/utils.js +15 -0
- package/constants/language-code.js +1 -0
- package/decorators/field.decorators.js +8 -1
- package/decorators/property.decorators.js +1 -0
- package/decorators/public-route.decorator.js +1 -0
- package/decorators/transform.decorators.d.ts +27 -0
- package/decorators/transform.decorators.js +29 -0
- package/decorators/translate.decorator.js +1 -0
- package/decorators/user.decorator.js +1 -0
- package/decorators/validator.decorators.d.ts +8 -18
- package/decorators/validator.decorators.js +22 -190
- package/filters/constraint-errors.js +1 -0
- package/helpers/common.helper.d.ts +13 -0
- package/helpers/common.helper.js +13 -0
- package/http-client/config/http-client.config.d.ts +15 -0
- package/http-client/config/http-client.config.js +25 -9
- package/http-client/decorators/http-client.decorators.d.ts +63 -0
- package/http-client/decorators/http-client.decorators.js +71 -3
- package/http-client/entities/http-log.entity.d.ts +229 -0
- package/http-client/entities/http-log.entity.js +6 -1
- package/http-client/errors/http-client.errors.d.ts +57 -0
- package/http-client/errors/http-client.errors.js +58 -0
- package/http-client/examples/advanced-usage.example.d.ts +41 -0
- package/http-client/examples/advanced-usage.example.js +68 -24
- package/http-client/examples/auth-with-waiting-lock.example.d.ts +31 -0
- package/http-client/examples/auth-with-waiting-lock.example.js +52 -5
- package/http-client/examples/basic-usage.example.d.ts +60 -0
- package/http-client/examples/basic-usage.example.js +60 -0
- package/http-client/examples/multi-api-configuration.example.d.ts +60 -0
- package/http-client/examples/multi-api-configuration.example.js +76 -5
- package/http-client/http-client.module.d.ts +13 -0
- package/http-client/http-client.module.js +19 -0
- package/http-client/index.js +8 -0
- package/http-client/interfaces/api-client-config.interface.d.ts +125 -0
- package/http-client/interfaces/api-client-config.interface.js +3 -0
- package/http-client/interfaces/http-client-config.interface.d.ts +60 -0
- package/http-client/services/api-client-registry.service.d.ts +57 -0
- package/http-client/services/api-client-registry.service.js +84 -1
- package/http-client/services/cache.service.d.ts +52 -0
- package/http-client/services/cache.service.js +72 -3
- package/http-client/services/circuit-breaker.service.d.ts +46 -0
- package/http-client/services/circuit-breaker.service.js +52 -0
- package/http-client/services/http-client.service.d.ts +67 -0
- package/http-client/services/http-client.service.js +105 -4
- package/http-client/services/http-log-query.service.d.ts +83 -0
- package/http-client/services/http-log-query.service.js +122 -1
- package/http-client/services/http-replay.service.d.ts +101 -0
- package/http-client/services/http-replay.service.js +86 -0
- package/http-client/services/log-cleanup.service.d.ts +63 -0
- package/http-client/services/log-cleanup.service.js +54 -2
- package/http-client/services/logging.service.d.ts +40 -0
- package/http-client/services/logging.service.js +53 -0
- package/http-client/utils/call-stack-extractor.util.d.ts +37 -0
- package/http-client/utils/call-stack-extractor.util.js +48 -0
- package/http-client/utils/context-extractor.util.d.ts +49 -0
- package/http-client/utils/context-extractor.util.js +52 -0
- package/http-client/utils/curl-generator.util.d.ts +21 -0
- package/http-client/utils/curl-generator.util.js +44 -3
- package/http-client/utils/request-id.util.d.ts +18 -0
- package/http-client/utils/request-id.util.js +20 -0
- package/http-client/utils/retry-recorder.util.d.ts +42 -0
- package/http-client/utils/retry-recorder.util.js +44 -0
- package/index.js +8 -0
- package/interceptors/translation-interceptor.service.js +5 -0
- package/package.json +1 -1
- package/providers/context.provider.js +2 -0
- package/providers/generator.provider.d.ts +4 -0
- package/providers/generator.provider.js +4 -0
- package/redis-lock/examples/lock-strategy.examples.d.ts +89 -0
- package/redis-lock/examples/lock-strategy.examples.js +130 -15
- package/redis-lock/index.js +3 -0
- package/redis-lock/redis-lock.decorator.d.ts +101 -0
- package/redis-lock/redis-lock.decorator.js +120 -0
- package/redis-lock/redis-lock.module.d.ts +60 -0
- package/redis-lock/redis-lock.module.js +46 -0
- package/redis-lock/redis-lock.service.d.ts +251 -0
- package/redis-lock/redis-lock.service.js +219 -3
- package/setup/bootstrap.setup.js +20 -0
- package/setup/mode.setup.d.ts +44 -0
- package/setup/mode.setup.js +44 -0
- package/setup/schedule.decorator.d.ts +226 -0
- package/setup/schedule.decorator.js +214 -1
- package/setup/worker.decorator.d.ts +86 -0
- package/setup/worker.decorator.js +88 -0
- package/shared/serviceRegistryModule.js +5 -1
- package/shared/services/api-config.service.d.ts +3 -0
- package/shared/services/api-config.service.js +20 -9
- package/validator-json/decorators.d.ts +17 -0
- package/validator-json/decorators.js +17 -2
- package/validator-json/default.d.ts +6 -0
- package/validator-json/default.js +30 -2
- package/validator-json/defaultConverters.js +1 -0
- package/validator-json/options.d.ts +23 -0
- package/validators/common-validators.d.ts +143 -0
- package/validators/common-validators.js +249 -0
- package/validators/custom-validate.examples.d.ts +23 -0
- package/validators/custom-validate.examples.js +78 -6
- package/validators/custom-validate.validator.d.ts +107 -0
- package/validators/custom-validate.validator.js +84 -0
- package/validators/index.d.ts +1 -0
- package/validators/index.js +1 -0
- package/validators/is-exists.validator.d.ts +11 -0
- package/validators/is-exists.validator.js +22 -0
- package/validators/is-unique.validator.d.ts +11 -0
- package/validators/is-unique.validator.js +31 -3
- package/validators/skip-empty.validator.d.ts +5 -0
- package/validators/skip-empty.validator.js +5 -0
- package/vault/interfaces/vault-options.interface.d.ts +9 -0
- package/vault/vault-config.loader.d.ts +30 -0
- package/vault/vault-config.loader.js +48 -1
- package/vault/vault-config.service.d.ts +53 -0
- package/vault/vault-config.service.js +57 -0
- package/vault/vault.module.d.ts +4 -0
- package/vault/vault.module.js +4 -0
- package/decorators/examples/validation-decorators.example.d.ts +0 -69
- package/decorators/examples/validation-decorators.example.js +0 -331
|
@@ -32,6 +32,10 @@ const curl_generator_util_1 = require("../utils/curl-generator.util");
|
|
|
32
32
|
const retry_recorder_util_1 = require("../utils/retry-recorder.util");
|
|
33
33
|
const request_id_util_1 = require("../utils/request-id.util");
|
|
34
34
|
const redis_lock_service_1 = require("../../redis-lock/redis-lock.service");
|
|
35
|
+
/**
|
|
36
|
+
* HTTP客户端服务
|
|
37
|
+
* 基于Spring RestTemplate的设计理念,集成axios-retry库
|
|
38
|
+
*/
|
|
35
39
|
let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
36
40
|
constructor(circuitBreakerService, loggingService, cacheService, redisLockService, config = {}) {
|
|
37
41
|
this.circuitBreakerService = circuitBreakerService;
|
|
@@ -50,6 +54,9 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
50
54
|
this.defaultConfig = this.mergeWithDefaults(config);
|
|
51
55
|
this.axiosInstance = this.createAxiosInstance();
|
|
52
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* 执行HTTP请求
|
|
59
|
+
*/
|
|
53
60
|
request(config, decoratorContext) {
|
|
54
61
|
return __awaiter(this, void 0, void 0, function* () {
|
|
55
62
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
@@ -59,16 +66,21 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
59
66
|
let circuitBreakerState;
|
|
60
67
|
let cacheHit = false;
|
|
61
68
|
try {
|
|
69
|
+
// 应用装饰器配置
|
|
62
70
|
const enhancedConfig = this.applyDecoratorConfig(config, decoratorContext);
|
|
71
|
+
// 获取装饰器配置
|
|
63
72
|
const decoratorConfigs = decoratorContext
|
|
64
73
|
? decorators_1.HttpDecoratorUtils.getAllDecoratorConfigs(decoratorContext.target, decoratorContext.propertyKey)
|
|
65
74
|
: {};
|
|
75
|
+
// 日志记录开始
|
|
66
76
|
const loggingOptions = decoratorConfigs.logging || this.defaultConfig.logging;
|
|
67
77
|
if (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.enabled) {
|
|
68
78
|
requestId = this.loggingService.logRequestStart(enhancedConfig, loggingOptions);
|
|
79
|
+
// 将requestId保存到config中
|
|
69
80
|
enhancedConfig.metadata = enhancedConfig.metadata || {};
|
|
70
81
|
enhancedConfig.metadata.requestId = requestId;
|
|
71
82
|
}
|
|
83
|
+
// 缓存检查
|
|
72
84
|
const cacheConfig = decoratorConfigs.cache || this.defaultConfig.cache;
|
|
73
85
|
if ((cacheConfig === null || cacheConfig === void 0 ? void 0 : cacheConfig.enabled) &&
|
|
74
86
|
this.shouldCacheRequest(enhancedConfig, cacheConfig)) {
|
|
@@ -78,15 +90,19 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
78
90
|
if (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.enabled) {
|
|
79
91
|
const databaseLogging = (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.databaseLog) ||
|
|
80
92
|
((_b = (_a = this.defaultConfig.logging) === null || _a === void 0 ? void 0 : _a.databaseLogging) === null || _b === void 0 ? void 0 : _b.enabled);
|
|
81
|
-
this.loggingService.logRequestSuccess(cachedResponse, startTime, requestId, loggingOptions, databaseLogging, undefined,
|
|
93
|
+
this.loggingService.logRequestSuccess(cachedResponse, startTime, requestId, loggingOptions, databaseLogging, undefined, // no retry records for cache hit
|
|
94
|
+
cacheHit, undefined, // circuit breaker state
|
|
95
|
+
decoratorContext);
|
|
82
96
|
}
|
|
83
97
|
return cachedResponse.data;
|
|
84
98
|
}
|
|
85
99
|
}
|
|
100
|
+
// 应用超时配置
|
|
86
101
|
const timeout = decoratorConfigs.timeout || this.defaultConfig.timeout;
|
|
87
102
|
if (timeout) {
|
|
88
103
|
enhancedConfig.timeout = timeout;
|
|
89
104
|
}
|
|
105
|
+
// 应用代理配置
|
|
90
106
|
const proxyConfig = decoratorConfigs.proxy || this.defaultConfig.proxy;
|
|
91
107
|
if (proxyConfig === null || proxyConfig === void 0 ? void 0 : proxyConfig.enabled) {
|
|
92
108
|
enhancedConfig.proxy = {
|
|
@@ -96,23 +112,29 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
96
112
|
auth: proxyConfig.auth,
|
|
97
113
|
};
|
|
98
114
|
}
|
|
115
|
+
// 配置axios-retry的onRetry回调以记录重试
|
|
99
116
|
if ((_c = this.defaultConfig.retry) === null || _c === void 0 ? void 0 : _c.enabled) {
|
|
100
117
|
const originalOnRetry = this.defaultConfig.retry.onRetry;
|
|
101
118
|
this.defaultConfig.retry.onRetry = (retryCount, error, requestConfig) => {
|
|
119
|
+
// 记录重试
|
|
102
120
|
const retryRecord = retry_recorder_util_1.RetryRecorder.recordRetry(retryCount, error, requestConfig, this.calculateRetryDelay(retryCount, this.defaultConfig.retry));
|
|
103
121
|
retryRecorder.addRecord(retryRecord);
|
|
122
|
+
// 调用原始回调
|
|
104
123
|
if (originalOnRetry) {
|
|
105
124
|
originalOnRetry(retryCount, error, requestConfig);
|
|
106
125
|
}
|
|
107
126
|
};
|
|
108
127
|
}
|
|
128
|
+
// 执行请求(带重试和熔断器)
|
|
109
129
|
const response = yield this.executeWithFeatures(enhancedConfig, decoratorConfigs, requestId, startTime, retryRecorder, (state) => {
|
|
110
130
|
circuitBreakerState = state;
|
|
111
131
|
});
|
|
132
|
+
// 缓存响应
|
|
112
133
|
if ((cacheConfig === null || cacheConfig === void 0 ? void 0 : cacheConfig.enabled) &&
|
|
113
134
|
this.shouldCacheRequest(enhancedConfig, cacheConfig)) {
|
|
114
135
|
yield this.cacheService.set(enhancedConfig, response, cacheConfig);
|
|
115
136
|
}
|
|
137
|
+
// 成功日志
|
|
116
138
|
if (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.enabled) {
|
|
117
139
|
const databaseLogging = (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.databaseLog) ||
|
|
118
140
|
((_e = (_d = this.defaultConfig.logging) === null || _d === void 0 ? void 0 : _d.databaseLogging) === null || _e === void 0 ? void 0 : _e.enabled);
|
|
@@ -121,6 +143,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
121
143
|
return response.data;
|
|
122
144
|
}
|
|
123
145
|
catch (error) {
|
|
146
|
+
// 错误日志
|
|
124
147
|
const loggingOptions = decoratorContext
|
|
125
148
|
? decorators_1.HttpDecoratorUtils.getLoggingOptions(decoratorContext.target, decoratorContext.propertyKey)
|
|
126
149
|
: this.defaultConfig.logging;
|
|
@@ -133,12 +156,21 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
133
156
|
}
|
|
134
157
|
});
|
|
135
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* 生成curl命令(动态生成,不存储)
|
|
161
|
+
*/
|
|
136
162
|
generateCurlCommand(config) {
|
|
137
163
|
return curl_generator_util_1.CurlGenerator.generateSimplifiedCurl(config);
|
|
138
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* 生成调试curl命令(动态生成,不存储)
|
|
167
|
+
*/
|
|
139
168
|
generateDebugCurlCommand(config, response) {
|
|
140
169
|
return curl_generator_util_1.CurlGenerator.generateDebugCurl(config, response);
|
|
141
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* 获取请求统计信息
|
|
173
|
+
*/
|
|
142
174
|
getStats() {
|
|
143
175
|
const avgResponseTime = this.requestStats.totalRequests > 0
|
|
144
176
|
? this.requestStats.totalResponseTime / this.requestStats.totalRequests
|
|
@@ -149,6 +181,9 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
149
181
|
100
|
|
150
182
|
: 0, circuitBreakerStats: this.circuitBreakerService.getAllStates(), cacheStats: this.cacheService.getStats() });
|
|
151
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* 重置统计信息
|
|
186
|
+
*/
|
|
152
187
|
resetStats() {
|
|
153
188
|
this.requestStats = {
|
|
154
189
|
totalRequests: 0,
|
|
@@ -159,6 +194,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
159
194
|
requestsByStatus: {},
|
|
160
195
|
};
|
|
161
196
|
}
|
|
197
|
+
// 便捷方法
|
|
162
198
|
get(url, config) {
|
|
163
199
|
return __awaiter(this, void 0, void 0, function* () {
|
|
164
200
|
return this.request(Object.assign(Object.assign({}, config), { method: 'GET', url }));
|
|
@@ -184,6 +220,15 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
184
220
|
return this.request(Object.assign(Object.assign({}, config), { method: 'DELETE', url }));
|
|
185
221
|
});
|
|
186
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* 带等待锁的认证请求方法
|
|
225
|
+
* 用于需要确保只有一个进程执行认证相关操作的场景
|
|
226
|
+
*
|
|
227
|
+
* @param config 请求配置
|
|
228
|
+
* @param tokenProvider token提供函数
|
|
229
|
+
* @param options 等待锁选项
|
|
230
|
+
* @returns 响应数据
|
|
231
|
+
*/
|
|
187
232
|
authRequest(config, tokenProvider, options) {
|
|
188
233
|
return __awaiter(this, void 0, void 0, function* () {
|
|
189
234
|
if (!this.redisLockService) {
|
|
@@ -192,9 +237,13 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
192
237
|
}
|
|
193
238
|
const { lockKey = `auth-request:${(0, request_id_util_1.generateRequestId)()}`, lockTimeout = 30000, waitTimeout = 60000, enableRetry = true, } = options || {};
|
|
194
239
|
try {
|
|
240
|
+
// 尝试获取锁并执行请求
|
|
195
241
|
const result = yield this.redisLockService.withLock(lockKey, () => __awaiter(this, void 0, void 0, function* () {
|
|
242
|
+
// 获取token
|
|
196
243
|
const token = yield tokenProvider();
|
|
244
|
+
// 添加认证头
|
|
197
245
|
const authConfig = Object.assign(Object.assign({}, config), { headers: Object.assign(Object.assign({}, config.headers), { Authorization: `Bearer ${token}` }) });
|
|
246
|
+
// 执行请求
|
|
198
247
|
return this.request(authConfig);
|
|
199
248
|
}), {
|
|
200
249
|
ttl: lockTimeout,
|
|
@@ -209,6 +258,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
209
258
|
}
|
|
210
259
|
catch (error) {
|
|
211
260
|
this.logger.error(`Auth request failed with lock ${lockKey}`, error);
|
|
261
|
+
// 如果是锁获取失败且启用重试,尝试无锁执行
|
|
212
262
|
if (enableRetry && error.message.includes('Failed to acquire lock')) {
|
|
213
263
|
this.logger.warn('Retrying auth request without lock');
|
|
214
264
|
const token = yield tokenProvider();
|
|
@@ -219,10 +269,20 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
219
269
|
}
|
|
220
270
|
});
|
|
221
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* 带等待锁的批量认证请求
|
|
274
|
+
* 用于需要批量执行认证相关操作但避免重复认证的场景
|
|
275
|
+
*
|
|
276
|
+
* @param requests 请求数组
|
|
277
|
+
* @param tokenProvider token提供函数
|
|
278
|
+
* @param options 等待锁选项
|
|
279
|
+
* @returns 响应数组
|
|
280
|
+
*/
|
|
222
281
|
authBatchRequest(requests, tokenProvider, options) {
|
|
223
282
|
return __awaiter(this, void 0, void 0, function* () {
|
|
224
283
|
if (!this.redisLockService) {
|
|
225
284
|
this.logger.warn('RedisLockService not available, proceeding batch auth requests without lock');
|
|
285
|
+
// 无锁批量执行
|
|
226
286
|
const token = yield tokenProvider();
|
|
227
287
|
const promises = requests.map((request) => __awaiter(this, void 0, void 0, function* () {
|
|
228
288
|
try {
|
|
@@ -238,8 +298,11 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
238
298
|
}
|
|
239
299
|
const { lockKey = `batch-auth-request:${(0, request_id_util_1.generateRequestId)()}`, lockTimeout = 60000, waitTimeout = 120000, maxConcurrency = 5, } = options || {};
|
|
240
300
|
try {
|
|
301
|
+
// 使用锁获取token并执行批量请求
|
|
241
302
|
const results = yield this.redisLockService.withLock(lockKey, () => __awaiter(this, void 0, void 0, function* () {
|
|
303
|
+
// 获取token(只获取一次)
|
|
242
304
|
const token = yield tokenProvider();
|
|
305
|
+
// 创建并发请求
|
|
243
306
|
const semaphore = new Array(maxConcurrency).fill(null);
|
|
244
307
|
const results = new Array(requests.length);
|
|
245
308
|
const executing = new Set();
|
|
@@ -259,6 +322,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
259
322
|
executing.delete(key);
|
|
260
323
|
}
|
|
261
324
|
});
|
|
325
|
+
// 创建并发的请求Promise
|
|
262
326
|
const promises = requests.map((request, index) => __awaiter(this, void 0, void 0, function* () {
|
|
263
327
|
return new Promise((resolve, reject) => {
|
|
264
328
|
const checkSlot = () => {
|
|
@@ -301,6 +365,9 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
301
365
|
}
|
|
302
366
|
});
|
|
303
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* 创建Axios实例并配置axios-retry
|
|
370
|
+
*/
|
|
304
371
|
createAxiosInstance() {
|
|
305
372
|
var _a, _b;
|
|
306
373
|
const instance = require('axios').create({
|
|
@@ -315,6 +382,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
315
382
|
}
|
|
316
383
|
: undefined,
|
|
317
384
|
});
|
|
385
|
+
// 配置axios-retry
|
|
318
386
|
if ((_b = this.defaultConfig.retry) === null || _b === void 0 ? void 0 : _b.enabled) {
|
|
319
387
|
(0, axios_retry_1.default)(instance, {
|
|
320
388
|
retries: this.defaultConfig.retry.retries || 3,
|
|
@@ -323,9 +391,9 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
323
391
|
retryCondition: this.defaultConfig.retry.retryCondition ||
|
|
324
392
|
((error) => {
|
|
325
393
|
if (!error.response)
|
|
326
|
-
return true;
|
|
394
|
+
return true; // 网络错误
|
|
327
395
|
const status = error.response.status;
|
|
328
|
-
return status >= 500 || status === 429;
|
|
396
|
+
return status >= 500 || status === 429; // 5xx错误或429限流
|
|
329
397
|
}),
|
|
330
398
|
shouldResetTimeout: this.defaultConfig.retry.shouldResetTimeout !== false,
|
|
331
399
|
onRetry: this.defaultConfig.retry.onRetry ||
|
|
@@ -335,14 +403,17 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
335
403
|
}),
|
|
336
404
|
});
|
|
337
405
|
}
|
|
406
|
+
// 设置请求拦截器
|
|
338
407
|
instance.interceptors.request.use((config) => {
|
|
339
408
|
config.headers = config.headers || {};
|
|
409
|
+
// 从ContextProvider获取上下文信息
|
|
340
410
|
const context = context_extractor_util_1.ContextExtractor.getHttpContext();
|
|
341
411
|
const requestId = context.requestId || (0, request_id_util_1.generateRequestId)();
|
|
342
412
|
config.headers['X-Request-ID'] = requestId;
|
|
343
413
|
if (context.userId) {
|
|
344
414
|
config.headers['X-User-ID'] = context.userId;
|
|
345
415
|
}
|
|
416
|
+
// 存储requestId到config中供后续使用
|
|
346
417
|
config.metadata = config.metadata || {};
|
|
347
418
|
config.metadata.requestId = requestId;
|
|
348
419
|
return config;
|
|
@@ -350,6 +421,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
350
421
|
this.logger.error('Request interceptor error', error);
|
|
351
422
|
return Promise.reject(error);
|
|
352
423
|
});
|
|
424
|
+
// 设置响应拦截器
|
|
353
425
|
instance.interceptors.response.use((response) => {
|
|
354
426
|
this.updateStats(response);
|
|
355
427
|
return response;
|
|
@@ -359,9 +431,13 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
359
431
|
});
|
|
360
432
|
return instance;
|
|
361
433
|
}
|
|
434
|
+
/**
|
|
435
|
+
* 执行带特性的请求(重试、熔断器等)
|
|
436
|
+
*/
|
|
362
437
|
executeWithFeatures(config, decoratorConfigs, requestId, startTime, retryRecorder, onCircuitBreakerStateChange) {
|
|
363
438
|
return __awaiter(this, void 0, void 0, function* () {
|
|
364
439
|
const requestFn = () => this.axiosInstance.request(config);
|
|
440
|
+
// 熔断器保护
|
|
365
441
|
const circuitBreakerConfig = decoratorConfigs.circuitBreaker || this.defaultConfig.circuitBreaker;
|
|
366
442
|
if (circuitBreakerConfig === null || circuitBreakerConfig === void 0 ? void 0 : circuitBreakerConfig.enabled) {
|
|
367
443
|
const circuitBreakerKey = this.generateCircuitBreakerKey(config);
|
|
@@ -372,29 +448,45 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
372
448
|
}
|
|
373
449
|
});
|
|
374
450
|
}
|
|
451
|
+
/**
|
|
452
|
+
* 计算重试延迟
|
|
453
|
+
*/
|
|
375
454
|
calculateRetryDelay(retryCount, retryConfig) {
|
|
376
455
|
if (retryConfig.retryDelay) {
|
|
377
456
|
return retryConfig.retryDelay(retryCount);
|
|
378
457
|
}
|
|
458
|
+
// 默认指数退避
|
|
379
459
|
return Math.pow(2, retryCount) * 1000;
|
|
380
460
|
}
|
|
461
|
+
/**
|
|
462
|
+
* 应用装饰器配置
|
|
463
|
+
*/
|
|
381
464
|
applyDecoratorConfig(config, decoratorContext) {
|
|
382
465
|
if (!decoratorContext)
|
|
383
466
|
return Object.assign({}, config);
|
|
384
467
|
const httpClientConfig = decorators_1.HttpDecoratorUtils.getHttpClientOptions(decoratorContext.target);
|
|
385
468
|
return Object.assign(Object.assign({}, config), httpClientConfig);
|
|
386
469
|
}
|
|
470
|
+
/**
|
|
471
|
+
* 判断是否应该缓存请求
|
|
472
|
+
*/
|
|
387
473
|
shouldCacheRequest(config, cacheConfig) {
|
|
388
474
|
var _a;
|
|
389
475
|
const method = (_a = config.method) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
390
476
|
return cacheConfig.cacheableMethods.includes(method || 'get');
|
|
391
477
|
}
|
|
478
|
+
/**
|
|
479
|
+
* 生成熔断器键
|
|
480
|
+
*/
|
|
392
481
|
generateCircuitBreakerKey(config) {
|
|
393
482
|
var _a;
|
|
394
483
|
const method = ((_a = config.method) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || 'UNKNOWN';
|
|
395
484
|
const url = new URL(config.url || '', this.defaultConfig.baseURL || 'http://localhost');
|
|
396
485
|
return `${method}:${url.host}${url.pathname}`;
|
|
397
486
|
}
|
|
487
|
+
/**
|
|
488
|
+
* 更新请求统计
|
|
489
|
+
*/
|
|
398
490
|
updateStats(response) {
|
|
399
491
|
var _a, _b;
|
|
400
492
|
this.requestStats.totalRequests++;
|
|
@@ -412,6 +504,9 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
412
504
|
this.requestStats.totalResponseTime += responseTime;
|
|
413
505
|
}
|
|
414
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* 更新错误统计
|
|
509
|
+
*/
|
|
415
510
|
updateErrorStats(error) {
|
|
416
511
|
var _a;
|
|
417
512
|
this.requestStats.totalRequests++;
|
|
@@ -427,6 +522,9 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
427
522
|
}
|
|
428
523
|
}
|
|
429
524
|
}
|
|
525
|
+
/**
|
|
526
|
+
* 合并默认配置
|
|
527
|
+
*/
|
|
430
528
|
mergeWithDefaults(config) {
|
|
431
529
|
const defaults = {
|
|
432
530
|
baseURL: process.env.HTTP_CLIENT_BASE_URL,
|
|
@@ -453,7 +551,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
453
551
|
},
|
|
454
552
|
cache: {
|
|
455
553
|
enabled: true,
|
|
456
|
-
defaultTtl: 300000,
|
|
554
|
+
defaultTtl: 300000, // 5分钟
|
|
457
555
|
cacheableMethods: ['get'],
|
|
458
556
|
cacheableStatusCodes: [200, 201, 202, 204, 301, 302, 304],
|
|
459
557
|
options: {
|
|
@@ -479,6 +577,9 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
479
577
|
};
|
|
480
578
|
return this.deepMerge(defaults, config);
|
|
481
579
|
}
|
|
580
|
+
/**
|
|
581
|
+
* 深度合并对象
|
|
582
|
+
*/
|
|
482
583
|
deepMerge(target, source) {
|
|
483
584
|
const result = Object.assign({}, target);
|
|
484
585
|
for (const key in source) {
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { DataSource } from 'typeorm';
|
|
2
2
|
import { HttpLogEntity, HttpLogQueryOptions, HttpLogStats } from '../entities/http-log.entity';
|
|
3
|
+
/**
|
|
4
|
+
* HTTP日志查询服务
|
|
5
|
+
*/
|
|
3
6
|
export declare class HttpLogQueryService {
|
|
4
7
|
private readonly dataSource?;
|
|
5
8
|
private readonly logger;
|
|
6
9
|
private logRepository;
|
|
7
10
|
constructor(dataSource?: DataSource);
|
|
11
|
+
/**
|
|
12
|
+
* 查询HTTP日志
|
|
13
|
+
*/
|
|
8
14
|
findLogs(options?: HttpLogQueryOptions): Promise<{
|
|
9
15
|
logs: HttpLogEntity[];
|
|
10
16
|
total: number;
|
|
@@ -12,8 +18,17 @@ export declare class HttpLogQueryService {
|
|
|
12
18
|
limit: number;
|
|
13
19
|
totalPages: number;
|
|
14
20
|
}>;
|
|
21
|
+
/**
|
|
22
|
+
* 根据ID查询单条日志
|
|
23
|
+
*/
|
|
15
24
|
findLogById(id: string, includeDetails?: boolean): Promise<HttpLogEntity | null>;
|
|
25
|
+
/**
|
|
26
|
+
* 根据请求ID查询日志
|
|
27
|
+
*/
|
|
16
28
|
findLogByRequestId(requestId: string): Promise<HttpLogEntity | null>;
|
|
29
|
+
/**
|
|
30
|
+
* 查询错误日志
|
|
31
|
+
*/
|
|
17
32
|
findErrorLogs(options?: {
|
|
18
33
|
startDate?: Date;
|
|
19
34
|
endDate?: Date;
|
|
@@ -25,6 +40,9 @@ export declare class HttpLogQueryService {
|
|
|
25
40
|
logs: HttpLogEntity[];
|
|
26
41
|
total: number;
|
|
27
42
|
}>;
|
|
43
|
+
/**
|
|
44
|
+
* 查询慢请求日志
|
|
45
|
+
*/
|
|
28
46
|
findSlowRequests(minResponseTime?: number, options?: {
|
|
29
47
|
page?: number;
|
|
30
48
|
limit?: number;
|
|
@@ -32,6 +50,9 @@ export declare class HttpLogQueryService {
|
|
|
32
50
|
logs: HttpLogEntity[];
|
|
33
51
|
total: number;
|
|
34
52
|
}>;
|
|
53
|
+
/**
|
|
54
|
+
* 查询重试日志
|
|
55
|
+
*/
|
|
35
56
|
findRetryLogs(options?: {
|
|
36
57
|
minRetries?: number;
|
|
37
58
|
page?: number;
|
|
@@ -40,6 +61,9 @@ export declare class HttpLogQueryService {
|
|
|
40
61
|
logs: HttpLogEntity[];
|
|
41
62
|
total: number;
|
|
42
63
|
}>;
|
|
64
|
+
/**
|
|
65
|
+
* 获取统计信息
|
|
66
|
+
*/
|
|
43
67
|
getStats(options?: {
|
|
44
68
|
startDate?: Date;
|
|
45
69
|
endDate?: Date;
|
|
@@ -47,30 +71,89 @@ export declare class HttpLogQueryService {
|
|
|
47
71
|
serviceName?: string;
|
|
48
72
|
groupBy?: 'hour' | 'day' | 'week';
|
|
49
73
|
}): Promise<HttpLogStats>;
|
|
74
|
+
/**
|
|
75
|
+
* 删除旧日志
|
|
76
|
+
*/
|
|
50
77
|
deleteOldLogs(daysToKeep?: number): Promise<number>;
|
|
78
|
+
/**
|
|
79
|
+
* 清空所有日志
|
|
80
|
+
*/
|
|
51
81
|
clearAllLogs(): Promise<number>;
|
|
82
|
+
/**
|
|
83
|
+
* 根据日志ID生成curl命令
|
|
84
|
+
* @param logId 日志ID
|
|
85
|
+
* @returns curl命令字符串
|
|
86
|
+
*/
|
|
52
87
|
generateCurlFromLog(logId: string): Promise<string | null>;
|
|
88
|
+
/**
|
|
89
|
+
* 根据请求ID生成curl命令
|
|
90
|
+
* @param requestId 请求ID
|
|
91
|
+
* @returns curl命令字符串
|
|
92
|
+
*/
|
|
53
93
|
generateCurlFromRequestId(requestId: string): Promise<string | null>;
|
|
94
|
+
/**
|
|
95
|
+
* 根据日志生成可重放的请求配置
|
|
96
|
+
* @param logId 日志ID
|
|
97
|
+
* @returns 请求配置对象
|
|
98
|
+
*/
|
|
54
99
|
generateReplayConfigFromLog(logId: string): Promise<any | null>;
|
|
100
|
+
/**
|
|
101
|
+
* 根据请求ID生成可重放的请求配置
|
|
102
|
+
* @param requestId 请求ID
|
|
103
|
+
* @returns 请求配置对象
|
|
104
|
+
*/
|
|
55
105
|
generateReplayConfigFromRequestId(requestId: string): Promise<any | null>;
|
|
106
|
+
/**
|
|
107
|
+
* 批量生成curl命令
|
|
108
|
+
* @param options 查询选项
|
|
109
|
+
* @returns curl命令数组
|
|
110
|
+
*/
|
|
56
111
|
generateBatchCurlCommands(options?: HttpLogQueryOptions): Promise<Array<{
|
|
57
112
|
logId: string;
|
|
58
113
|
requestId?: string;
|
|
59
114
|
curlCommand: string;
|
|
60
115
|
}>>;
|
|
116
|
+
/**
|
|
117
|
+
* 获取日志的完整重放信息
|
|
118
|
+
* @param logId 日志ID
|
|
119
|
+
* @returns 包含curl命令和重放配置的对象
|
|
120
|
+
*/
|
|
61
121
|
getLogReplayInfo(logId: string): Promise<{
|
|
62
122
|
log: HttpLogEntity;
|
|
63
123
|
curlCommand: string | null;
|
|
64
124
|
replayConfig: any | null;
|
|
65
125
|
} | null>;
|
|
126
|
+
/**
|
|
127
|
+
* 根据请求ID获取日志的完整重放信息
|
|
128
|
+
* @param requestId 请求ID
|
|
129
|
+
* @returns 包含curl命令和重放配置的对象
|
|
130
|
+
*/
|
|
66
131
|
getLogReplayInfoByRequestId(requestId: string): Promise<{
|
|
67
132
|
log: HttpLogEntity;
|
|
68
133
|
curlCommand: string | null;
|
|
69
134
|
replayConfig: any | null;
|
|
70
135
|
} | null>;
|
|
136
|
+
/**
|
|
137
|
+
* 初始化仓库
|
|
138
|
+
*/
|
|
71
139
|
private initializeRepository;
|
|
140
|
+
/**
|
|
141
|
+
* 计算响应时间百分位数
|
|
142
|
+
*/
|
|
72
143
|
private calculatePercentiles;
|
|
144
|
+
/**
|
|
145
|
+
* 格式化统计结果
|
|
146
|
+
*/
|
|
73
147
|
private formatStats;
|
|
148
|
+
/**
|
|
149
|
+
* 构建查询
|
|
150
|
+
*/
|
|
74
151
|
private buildQuery;
|
|
152
|
+
/**
|
|
153
|
+
* 清理敏感信息用于生成curl命令
|
|
154
|
+
* 移除或替换敏感的请求头和认证信息
|
|
155
|
+
* @param headers 原始请求头
|
|
156
|
+
* @returns 清理后的请求头
|
|
157
|
+
*/
|
|
75
158
|
private sanitizeHeadersForCurl;
|
|
76
159
|
}
|