@nest-omni/core 4.1.3-3 → 4.1.3-31
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 +1 -0
- package/audit/audit.module.js +51 -2
- package/audit/controllers/audit.controller.d.ts +57 -1
- package/audit/controllers/audit.controller.js +43 -0
- package/audit/decorators/audit-action.decorator.d.ts +74 -0
- package/audit/decorators/audit-action.decorator.js +42 -0
- package/audit/decorators/audit-controller.decorator.d.ts +1 -1
- package/audit/decorators/audit-controller.decorator.js +2 -2
- package/audit/decorators/audit-operation.decorator.d.ts +0 -7
- package/audit/decorators/audit-operation.decorator.js +0 -7
- package/audit/decorators/entity-audit.decorator.d.ts +78 -2
- package/audit/decorators/entity-audit.decorator.js +145 -4
- package/audit/decorators/index.d.ts +2 -0
- package/audit/decorators/index.js +2 -0
- package/audit/dto/audit-action-query.dto.d.ts +13 -0
- package/audit/dto/audit-action-query.dto.js +77 -0
- package/audit/dto/index.d.ts +1 -0
- package/audit/dto/index.js +1 -0
- package/audit/entities/audit-action-summary.entity.d.ts +23 -0
- package/audit/entities/audit-action-summary.entity.js +101 -0
- package/audit/entities/entity-audit-log.entity.d.ts +7 -2
- package/audit/entities/entity-audit-log.entity.js +45 -9
- package/audit/entities/entity-transaction.entity.d.ts +8 -2
- package/audit/entities/entity-transaction.entity.js +39 -3
- package/audit/entities/index.d.ts +3 -0
- package/audit/entities/index.js +3 -0
- package/audit/entities/manual-operation-log.entity.d.ts +0 -2
- package/audit/entities/manual-operation-log.entity.js +8 -9
- package/audit/enums/audit.enums.d.ts +14 -6
- package/audit/enums/audit.enums.js +18 -9
- package/audit/examples/decorator-value-mapping.example.d.ts +70 -0
- package/audit/examples/decorator-value-mapping.example.js +414 -0
- package/audit/index.d.ts +5 -1
- package/audit/index.js +29 -2
- package/audit/interceptors/audit-action.interceptor.d.ts +39 -0
- package/audit/interceptors/audit-action.interceptor.js +217 -0
- package/audit/interceptors/audit.interceptor.d.ts +1 -0
- package/audit/interceptors/audit.interceptor.js +19 -11
- package/audit/interceptors/index.d.ts +1 -0
- package/audit/interceptors/index.js +1 -0
- package/audit/interfaces/audit.interfaces.d.ts +132 -4
- package/audit/services/audit-action.service.d.ts +142 -0
- package/audit/services/audit-action.service.js +246 -0
- package/audit/services/audit-context.service.d.ts +91 -0
- package/audit/services/audit-context.service.js +170 -0
- package/audit/services/entity-audit.service.d.ts +220 -9
- package/audit/services/entity-audit.service.js +761 -72
- package/audit/services/index.d.ts +3 -0
- package/audit/services/index.js +3 -0
- package/audit/services/manual-audit-log.service.d.ts +23 -23
- package/audit/services/manual-audit-log.service.js +34 -57
- package/audit/services/multi-database.service.d.ts +0 -5
- package/audit/services/multi-database.service.js +0 -24
- package/audit/services/operation-description.service.d.ts +14 -3
- package/audit/services/operation-description.service.js +165 -26
- package/audit/services/transaction-audit.service.d.ts +1 -0
- package/audit/services/transaction-audit.service.js +12 -9
- package/audit/subscribers/entity-audit.subscriber.d.ts +5 -0
- package/audit/subscribers/entity-audit.subscriber.js +69 -5
- package/cache/cache.module.d.ts +7 -8
- package/cache/cache.module.js +15 -13
- package/cache/cache.service.d.ts +6 -4
- package/cache/cache.service.js +24 -12
- package/cache/decorators/cache-put.decorator.js +5 -4
- package/cache/dependencies/callback.dependency.js +9 -0
- package/cache/dependencies/db.dependency.d.ts +43 -12
- package/cache/dependencies/db.dependency.js +46 -18
- package/cache/dependencies/tag.dependency.d.ts +31 -4
- package/cache/dependencies/tag.dependency.js +100 -11
- package/cache/entities/index.d.ts +1 -0
- package/cache/entities/index.js +17 -0
- package/cache/entities/typeorm-cache.entity.d.ts +71 -0
- package/cache/entities/typeorm-cache.entity.js +110 -0
- package/cache/index.d.ts +2 -1
- package/cache/index.js +19 -2
- package/cache/interfaces/cache-options.interface.d.ts +8 -0
- package/cache/providers/index.d.ts +2 -1
- package/cache/providers/index.js +2 -1
- package/cache/providers/lrucache.provider.d.ts +77 -0
- package/cache/providers/lrucache.provider.js +228 -0
- package/cache/providers/redis-cache.provider.d.ts +1 -0
- package/cache/providers/redis-cache.provider.js +8 -6
- package/cache/providers/typeorm-cache.provider.d.ts +211 -0
- package/cache/providers/typeorm-cache.provider.js +483 -0
- package/common/boilerplate.polyfill.d.ts +1 -0
- package/common/boilerplate.polyfill.js +18 -1
- package/common/helpers/validation-metadata-helper.d.ts +112 -0
- package/common/helpers/validation-metadata-helper.js +164 -0
- package/common/index.d.ts +1 -0
- package/common/index.js +4 -0
- package/decorators/examples/field-i18n.example.d.ts +294 -0
- package/decorators/examples/field-i18n.example.js +478 -0
- package/decorators/field.decorators.d.ts +95 -3
- package/decorators/field.decorators.js +152 -18
- package/decorators/transform.decorators.d.ts +0 -2
- package/decorators/transform.decorators.js +0 -23
- package/decorators/translate.decorator.d.ts +26 -0
- package/decorators/translate.decorator.js +26 -1
- package/email-log/email-log.constants.d.ts +8 -0
- package/email-log/email-log.constants.js +11 -0
- package/email-log/email-log.module.d.ts +47 -0
- package/email-log/email-log.module.js +140 -0
- package/email-log/index.d.ts +11 -0
- package/email-log/index.js +48 -0
- package/email-log/interfaces/email-log-options.interface.d.ts +61 -0
- package/email-log/interfaces/email-log-options.interface.js +134 -0
- package/email-log/interfaces/email-log-transport.interface.d.ts +20 -0
- package/email-log/interfaces/email-log-transport.interface.js +2 -0
- package/email-log/interfaces/index.d.ts +2 -0
- package/email-log/interfaces/index.js +18 -0
- package/email-log/providers/email-provider.d.ts +42 -0
- package/email-log/providers/email-provider.js +127 -0
- package/email-log/providers/index.d.ts +1 -0
- package/email-log/providers/index.js +17 -0
- package/email-log/services/email-log-alert.service.d.ts +46 -0
- package/email-log/services/email-log-alert.service.js +162 -0
- package/email-log/services/email-log-formatter.service.d.ts +78 -0
- package/email-log/services/email-log-formatter.service.js +442 -0
- package/email-log/services/email-log-logger.service.d.ts +85 -0
- package/email-log/services/email-log-logger.service.js +168 -0
- package/email-log/services/email-log-rate-limiter.service.d.ts +42 -0
- package/email-log/services/email-log-rate-limiter.service.js +110 -0
- package/email-log/services/email-log-transport.service.d.ts +80 -0
- package/email-log/services/email-log-transport.service.js +271 -0
- package/email-log/services/index.d.ts +5 -0
- package/email-log/services/index.js +21 -0
- package/email-log/transports/index.d.ts +1 -0
- package/email-log/transports/index.js +17 -0
- package/email-log/transports/pino-email.transport.d.ts +56 -0
- package/email-log/transports/pino-email.transport.js +188 -0
- package/email-log/utils/index.d.ts +2 -0
- package/email-log/utils/index.js +18 -0
- package/email-log/utils/log-level.helper.d.ts +46 -0
- package/email-log/utils/log-level.helper.js +74 -0
- package/email-log/utils/pino-transport.utils.d.ts +135 -0
- package/email-log/utils/pino-transport.utils.js +238 -0
- package/file-upload/controllers/file-access.controller.d.ts +23 -0
- package/file-upload/controllers/file-access.controller.js +128 -0
- package/file-upload/decorators/column.decorator.d.ts +151 -0
- package/file-upload/decorators/column.decorator.js +273 -0
- package/file-upload/decorators/csv-data.decorator.d.ts +30 -0
- package/file-upload/decorators/csv-data.decorator.js +85 -0
- package/file-upload/decorators/csv-import.decorator.d.ts +34 -0
- package/file-upload/decorators/csv-import.decorator.js +24 -0
- package/file-upload/decorators/examples/column-mapping.example.d.ts +76 -0
- package/file-upload/decorators/examples/column-mapping.example.js +122 -0
- package/file-upload/decorators/excel-data.decorator.d.ts +30 -0
- package/file-upload/decorators/excel-data.decorator.js +85 -0
- package/file-upload/decorators/file-upload.decorator.d.ts +83 -0
- package/file-upload/decorators/file-upload.decorator.js +172 -0
- package/file-upload/decorators/index.d.ts +5 -0
- package/file-upload/decorators/index.js +38 -0
- package/file-upload/decorators/process.decorator.d.ts +40 -0
- package/file-upload/decorators/process.decorator.js +52 -0
- package/file-upload/decorators/validate-data.decorator.d.ts +91 -0
- package/file-upload/decorators/validate-data.decorator.js +39 -0
- package/file-upload/dto/create-file.dto.d.ts +24 -0
- package/file-upload/dto/create-file.dto.js +112 -0
- package/file-upload/dto/find-files.dto.d.ts +15 -0
- package/file-upload/dto/find-files.dto.js +76 -0
- package/file-upload/dto/index.d.ts +4 -0
- package/file-upload/dto/index.js +20 -0
- package/file-upload/dto/pagination.dto.d.ts +7 -0
- package/file-upload/dto/pagination.dto.js +39 -0
- package/file-upload/dto/update-file.dto.d.ts +15 -0
- package/file-upload/dto/update-file.dto.js +67 -0
- package/file-upload/entities/file-metadata.entity.d.ts +25 -0
- package/file-upload/entities/file-metadata.entity.js +76 -0
- package/file-upload/entities/file.entity.d.ts +114 -0
- package/file-upload/entities/file.entity.js +350 -0
- package/file-upload/entities/index.d.ts +2 -0
- package/file-upload/entities/index.js +18 -0
- package/file-upload/enums/file-type.enum.d.ts +72 -0
- package/file-upload/enums/file-type.enum.js +212 -0
- package/file-upload/exceptions/file-upload.exception.d.ts +57 -0
- package/file-upload/exceptions/file-upload.exception.js +120 -0
- package/file-upload/exceptions/index.d.ts +1 -0
- package/file-upload/exceptions/index.js +17 -0
- package/file-upload/file-upload.module.d.ts +89 -0
- package/file-upload/file-upload.module.js +292 -0
- package/file-upload/index.d.ts +37 -0
- package/file-upload/index.js +77 -0
- package/file-upload/interceptors/file-upload.interceptor.d.ts +101 -0
- package/file-upload/interceptors/file-upload.interceptor.js +594 -0
- package/file-upload/interceptors/index.d.ts +1 -0
- package/file-upload/interceptors/index.js +17 -0
- package/file-upload/interfaces/custom-file-type.interface.d.ts +72 -0
- package/file-upload/interfaces/custom-file-type.interface.js +2 -0
- package/file-upload/interfaces/file-buffer.interface.d.ts +72 -0
- package/file-upload/interfaces/file-buffer.interface.js +2 -0
- package/file-upload/interfaces/file-entity.interface.d.ts +142 -0
- package/file-upload/interfaces/file-entity.interface.js +28 -0
- package/file-upload/interfaces/file-metadata.interface.d.ts +21 -0
- package/file-upload/interfaces/file-metadata.interface.js +2 -0
- package/file-upload/interfaces/file-processor.interface.d.ts +93 -0
- package/file-upload/interfaces/file-processor.interface.js +2 -0
- package/file-upload/interfaces/file-upload-options.interface.d.ts +74 -0
- package/file-upload/interfaces/file-upload-options.interface.js +5 -0
- package/file-upload/interfaces/index.d.ts +7 -0
- package/file-upload/interfaces/index.js +24 -0
- package/file-upload/interfaces/processor-options.interface.d.ts +102 -0
- package/file-upload/interfaces/processor-options.interface.js +2 -0
- package/file-upload/interfaces/storage-provider.interface.d.ts +239 -0
- package/file-upload/interfaces/storage-provider.interface.js +2 -0
- package/file-upload/interfaces/upload-options.interface.d.ts +19 -0
- package/file-upload/interfaces/upload-options.interface.js +2 -0
- package/file-upload/processors/csv.processor.d.ts +98 -0
- package/file-upload/processors/csv.processor.js +391 -0
- package/file-upload/processors/excel.processor.d.ts +130 -0
- package/file-upload/processors/excel.processor.js +547 -0
- package/file-upload/processors/image.processor.d.ts +199 -0
- package/file-upload/processors/image.processor.js +377 -0
- package/file-upload/providers/index.d.ts +2 -0
- package/file-upload/providers/index.js +18 -0
- package/file-upload/providers/local-storage.provider.d.ts +98 -0
- package/file-upload/providers/local-storage.provider.js +484 -0
- package/file-upload/providers/s3-storage.provider.d.ts +87 -0
- package/file-upload/providers/s3-storage.provider.js +455 -0
- package/file-upload/services/file-signature-validator.service.d.ts +118 -0
- package/file-upload/services/file-signature-validator.service.js +376 -0
- package/file-upload/services/file.service.d.ts +193 -0
- package/file-upload/services/file.service.js +638 -0
- package/file-upload/services/index.d.ts +4 -0
- package/file-upload/services/index.js +20 -0
- package/file-upload/services/malicious-file-detector.service.d.ts +300 -0
- package/file-upload/services/malicious-file-detector.service.js +1234 -0
- package/file-upload/services/mime-registry.service.d.ts +47 -0
- package/file-upload/services/mime-registry.service.js +167 -0
- package/file-upload/utils/checksum.util.d.ts +28 -0
- package/file-upload/utils/checksum.util.js +65 -0
- package/file-upload/utils/dynamic-import.util.d.ts +54 -0
- package/file-upload/utils/dynamic-import.util.js +156 -0
- package/file-upload/utils/filename.util.d.ts +59 -0
- package/file-upload/utils/filename.util.js +184 -0
- package/file-upload/utils/filepath.util.d.ts +70 -0
- package/file-upload/utils/filepath.util.js +152 -0
- package/file-upload/utils/index.d.ts +4 -0
- package/file-upload/utils/index.js +20 -0
- package/filters/bad-request.filter.d.ts +9 -0
- package/filters/bad-request.filter.js +57 -16
- package/http-client/config/http-client.config.d.ts +5 -0
- package/http-client/config/http-client.config.js +27 -14
- package/http-client/decorators/http-client.decorators.d.ts +7 -28
- package/http-client/decorators/http-client.decorators.js +124 -99
- package/http-client/entities/http-log.entity.d.ts +0 -20
- package/http-client/entities/http-log.entity.js +1 -21
- package/http-client/examples/advanced-usage.example.d.ts +4 -5
- package/http-client/examples/advanced-usage.example.js +7 -59
- package/http-client/examples/axios-config-extended.example.d.ts +17 -0
- package/http-client/examples/axios-config-extended.example.js +311 -0
- 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/index.d.ts +2 -0
- package/http-client/examples/index.js +2 -0
- package/http-client/examples/proxy-from-environment.example.d.ts +133 -0
- package/http-client/examples/proxy-from-environment.example.js +409 -0
- package/http-client/examples/ssl-certificate.example.d.ts +47 -0
- package/http-client/examples/ssl-certificate.example.js +432 -0
- package/http-client/http-client.module.d.ts +43 -2
- package/http-client/http-client.module.js +150 -90
- package/http-client/index.d.ts +1 -1
- package/http-client/interfaces/api-client-config.interface.d.ts +24 -103
- package/http-client/interfaces/http-client-config.interface.d.ts +137 -62
- package/http-client/services/api-client-registry.service.d.ts +8 -21
- package/http-client/services/api-client-registry.service.js +31 -282
- 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 +85 -23
- package/http-client/services/http-client.service.js +512 -168
- 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 +69 -16
- package/http-client/services/logging.service.js +290 -170
- 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/context-extractor.util.d.ts +2 -0
- package/http-client/utils/context-extractor.util.js +17 -3
- package/http-client/utils/curl-generator.util.js +2 -5
- package/http-client/utils/index.d.ts +2 -0
- package/http-client/utils/index.js +2 -0
- package/http-client/utils/proxy-environment.util.d.ts +42 -0
- package/http-client/utils/proxy-environment.util.js +154 -0
- 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 +118 -0
- package/http-client/utils/security-validator.util.js +354 -0
- package/index.d.ts +4 -1
- package/index.js +6 -1
- package/interceptors/translation-interceptor.service.d.ts +7 -0
- package/interceptors/translation-interceptor.service.js +40 -8
- package/ip-filter/constants.d.ts +21 -0
- package/ip-filter/constants.js +24 -0
- package/ip-filter/decorators/index.d.ts +1 -0
- package/ip-filter/decorators/index.js +17 -0
- package/ip-filter/decorators/ip-filter.decorator.d.ts +58 -0
- package/ip-filter/decorators/ip-filter.decorator.js +79 -0
- package/ip-filter/guards/index.d.ts +1 -0
- package/ip-filter/guards/index.js +17 -0
- package/ip-filter/guards/ip-filter.guard.d.ts +62 -0
- package/ip-filter/guards/ip-filter.guard.js +174 -0
- package/ip-filter/index.d.ts +7 -0
- package/ip-filter/index.js +23 -0
- package/ip-filter/interfaces/index.d.ts +4 -0
- package/ip-filter/interfaces/index.js +20 -0
- package/ip-filter/interfaces/ip-filter-async-options.interface.d.ts +15 -0
- package/ip-filter/interfaces/ip-filter-async-options.interface.js +2 -0
- package/ip-filter/interfaces/ip-filter-metadata.interface.d.ts +26 -0
- package/ip-filter/interfaces/ip-filter-metadata.interface.js +2 -0
- package/ip-filter/interfaces/ip-filter-options.interface.d.ts +34 -0
- package/ip-filter/interfaces/ip-filter-options.interface.js +2 -0
- package/ip-filter/interfaces/ip-rule.interface.d.ts +36 -0
- package/ip-filter/interfaces/ip-rule.interface.js +2 -0
- package/ip-filter/ip-filter.module.d.ts +55 -0
- package/ip-filter/ip-filter.module.js +105 -0
- package/ip-filter/services/index.d.ts +1 -0
- package/ip-filter/services/index.js +17 -0
- package/ip-filter/services/ip-filter.service.d.ts +92 -0
- package/ip-filter/services/ip-filter.service.js +238 -0
- package/ip-filter/utils/index.d.ts +1 -0
- package/ip-filter/utils/index.js +17 -0
- package/ip-filter/utils/ip-utils.d.ts +61 -0
- package/ip-filter/utils/ip-utils.js +162 -0
- package/package.json +34 -29
- package/providers/context.provider.d.ts +9 -0
- package/providers/context.provider.js +13 -0
- package/redis-lock/comprehensive-lock-cleanup.service.d.ts +94 -0
- package/redis-lock/comprehensive-lock-cleanup.service.js +253 -0
- package/redis-lock/index.d.ts +2 -0
- package/redis-lock/index.js +5 -1
- package/redis-lock/lock-heartbeat.service.d.ts +80 -0
- package/redis-lock/lock-heartbeat.service.js +232 -0
- package/redis-lock/redis-lock.module.d.ts +6 -0
- package/redis-lock/redis-lock.module.js +136 -77
- package/redis-lock/redis-lock.service.d.ts +31 -0
- package/redis-lock/redis-lock.service.js +124 -17
- package/setup/bootstrap.setup.d.ts +2 -1
- package/setup/bootstrap.setup.js +3 -2
- package/setup/index.d.ts +1 -0
- package/setup/index.js +1 -0
- package/setup/run-in-mode.decorator.d.ts +56 -0
- package/setup/run-in-mode.decorator.js +92 -0
- package/setup/schedule.decorator.d.ts +1 -0
- package/setup/schedule.decorator.js +28 -13
- package/setup/worker.decorator.js +10 -1
- package/shared/index.d.ts +1 -1
- package/shared/index.js +1 -1
- package/shared/{serviceRegistryModule.js → service-registry.module.js} +28 -17
- package/shared/services/api-config.service.d.ts +41 -0
- package/shared/services/api-config.service.js +175 -8
- package/shared/services/index.d.ts +0 -1
- package/shared/services/index.js +0 -1
- package/validators/custom-validate.validator.d.ts +1 -0
- package/validators/custom-validate.validator.js +1 -0
- package/validators/file-mimetype.validator.d.ts +0 -2
- package/validators/file-mimetype.validator.js +4 -6
- package/validators/is-exists.validator.d.ts +15 -6
- package/validators/is-exists.validator.js +8 -7
- package/validators/is-unique.validator.d.ts +22 -7
- package/validators/is-unique.validator.js +41 -17
- package/vault/vault-config.service.js +1 -1
- package/cache/providers/memory-cache.provider.d.ts +0 -49
- package/cache/providers/memory-cache.provider.js +0 -197
- package/http-client/services/cache.service.d.ts +0 -76
- package/http-client/services/cache.service.js +0 -333
- package/shared/services/validator.service.d.ts +0 -3
- package/shared/services/validator.service.js +0 -20
- /package/shared/{serviceRegistryModule.d.ts → service-registry.module.d.ts} +0 -0
|
@@ -8,6 +8,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
8
8
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
11
14
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
15
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
16
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -17,30 +20,45 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
17
20
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
21
|
});
|
|
19
22
|
};
|
|
23
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
24
|
+
var t = {};
|
|
25
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
26
|
+
t[p] = s[p];
|
|
27
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
28
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
29
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
30
|
+
t[p[i]] = s[p[i]];
|
|
31
|
+
}
|
|
32
|
+
return t;
|
|
33
|
+
};
|
|
20
34
|
var HttpClientService_1;
|
|
21
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
36
|
exports.HttpClientService = void 0;
|
|
23
37
|
const common_1 = require("@nestjs/common");
|
|
24
38
|
const axios_retry_1 = require("axios-retry");
|
|
25
|
-
const
|
|
39
|
+
const api_client_config_interface_1 = require("../interfaces/api-client-config.interface");
|
|
26
40
|
const circuit_breaker_service_1 = require("./circuit-breaker.service");
|
|
27
41
|
const logging_service_1 = require("./logging.service");
|
|
28
|
-
const cache_service_1 = require("./cache.service");
|
|
29
42
|
const decorators_1 = require("../decorators");
|
|
30
43
|
const context_extractor_util_1 = require("../utils/context-extractor.util");
|
|
31
44
|
const curl_generator_util_1 = require("../utils/curl-generator.util");
|
|
45
|
+
const call_stack_extractor_util_1 = require("../utils/call-stack-extractor.util");
|
|
32
46
|
const retry_recorder_util_1 = require("../utils/retry-recorder.util");
|
|
33
47
|
const request_id_util_1 = require("../utils/request-id.util");
|
|
48
|
+
const proxy_environment_util_1 = require("../utils/proxy-environment.util");
|
|
34
49
|
const redis_lock_service_1 = require("../../redis-lock/redis-lock.service");
|
|
50
|
+
const security_validator_util_1 = require("../utils/security-validator.util");
|
|
35
51
|
/**
|
|
36
52
|
* HTTP客户端服务
|
|
37
53
|
* 基于Spring RestTemplate的设计理念,集成axios-retry库
|
|
54
|
+
* 支持两种创建模式:
|
|
55
|
+
* 1. 直接创建: 用于简单的HTTP请求场景
|
|
56
|
+
* 2. API客户端模式: 用于需要认证、统计等高级功能的API客户端
|
|
38
57
|
*/
|
|
39
58
|
let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
40
|
-
constructor(circuitBreakerService, loggingService,
|
|
59
|
+
constructor(circuitBreakerService, loggingService, redisLockService, config = {}, clientName, authConfig) {
|
|
41
60
|
this.circuitBreakerService = circuitBreakerService;
|
|
42
61
|
this.loggingService = loggingService;
|
|
43
|
-
this.cacheService = cacheService;
|
|
44
62
|
this.redisLockService = redisLockService;
|
|
45
63
|
this.logger = new common_1.Logger(HttpClientService_1.name);
|
|
46
64
|
this.requestStats = {
|
|
@@ -48,55 +66,149 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
48
66
|
successfulRequests: 0,
|
|
49
67
|
failedRequests: 0,
|
|
50
68
|
totalResponseTime: 0,
|
|
69
|
+
averageResponseTime: 0,
|
|
51
70
|
requestsByMethod: {},
|
|
52
71
|
requestsByStatus: {},
|
|
53
72
|
};
|
|
54
73
|
this.defaultConfig = this.mergeWithDefaults(config);
|
|
74
|
+
this.clientName = clientName;
|
|
75
|
+
this.authConfig = authConfig;
|
|
55
76
|
this.axiosInstance = this.createAxiosInstance();
|
|
56
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* 静态工厂方法:创建API客户端模式的 HttpClientService
|
|
80
|
+
* @param dependencies 依赖服务
|
|
81
|
+
* @param config API客户端配置
|
|
82
|
+
* @returns HttpClientService 实例
|
|
83
|
+
*/
|
|
84
|
+
static createApiClient(dependencies, config) {
|
|
85
|
+
// 构建配置,只在值有效时才覆盖
|
|
86
|
+
const mergedConfig = Object.assign({}, config.httpConfig);
|
|
87
|
+
// 只在显式提供且值有效时才覆盖
|
|
88
|
+
if (config.baseURL !== undefined) {
|
|
89
|
+
mergedConfig.baseURL = config.baseURL;
|
|
90
|
+
}
|
|
91
|
+
if (config.timeout !== undefined) {
|
|
92
|
+
mergedConfig.timeout = config.timeout;
|
|
93
|
+
}
|
|
94
|
+
return new HttpClientService_1(dependencies.circuitBreakerService, dependencies.loggingService, dependencies.redisLockService, mergedConfig, config.name, config.auth);
|
|
95
|
+
}
|
|
57
96
|
/**
|
|
58
97
|
* 执行HTTP请求
|
|
98
|
+
* @param config 请求配置
|
|
99
|
+
* @param decoratorContext 装饰器上下文
|
|
100
|
+
* @param clientName 客户端名称
|
|
101
|
+
* @param returnOptions 返回选项
|
|
102
|
+
* - returnType: 'data'(默认)只返回response.data
|
|
103
|
+
* - returnType: 'full'返回完整AxiosResponse对象
|
|
104
|
+
* - returnType: 'custom'使用自定义转换函数
|
|
105
|
+
* - transform: 自定义转换函数,接收完整response返回任意数据
|
|
59
106
|
*/
|
|
60
|
-
request(config, decoratorContext) {
|
|
107
|
+
request(config, decoratorContext, clientName, returnOptions) {
|
|
61
108
|
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
109
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
110
|
+
// Use the instance's clientName as fallback if not provided
|
|
111
|
+
const effectiveClientName = clientName || this.clientName;
|
|
112
|
+
// If no decorator context provided, try to get it from CallStackExtractor
|
|
113
|
+
// This allows decorators on service methods to pass context to HTTP client
|
|
114
|
+
const effectiveDecoratorContext = decoratorContext || call_stack_extractor_util_1.CallStackExtractor.getDecoratorContext();
|
|
115
|
+
// ========== 安全验证开始 ==========
|
|
116
|
+
// 构造完整URL进行验证
|
|
117
|
+
const requestURL = config.url || '';
|
|
118
|
+
const baseURL = config.baseURL || this.defaultConfig.baseURL || '';
|
|
119
|
+
// 构建完整的URL用于验证
|
|
120
|
+
let fullURL = requestURL;
|
|
121
|
+
if (requestURL &&
|
|
122
|
+
!requestURL.startsWith('http://') &&
|
|
123
|
+
!requestURL.startsWith('https://') &&
|
|
124
|
+
baseURL) {
|
|
125
|
+
// 处理相对URL
|
|
126
|
+
try {
|
|
127
|
+
fullURL = new URL(requestURL, baseURL).href;
|
|
128
|
+
}
|
|
129
|
+
catch (_o) {
|
|
130
|
+
// 如果URL构建失败,使用原始URL
|
|
131
|
+
fullURL = requestURL;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// 执行URL安全验证(只对完整URL进行验证)
|
|
135
|
+
if (fullURL &&
|
|
136
|
+
(fullURL.startsWith('http://') || fullURL.startsWith('https://'))) {
|
|
137
|
+
const sanitizeResult = security_validator_util_1.SecurityValidator.sanitizeURL(fullURL, {
|
|
138
|
+
urlConfig: (_a = this.defaultConfig.security) === null || _a === void 0 ? void 0 : _a.urlValidation,
|
|
139
|
+
ssrfConfig: (_b = this.defaultConfig.security) === null || _b === void 0 ? void 0 : _b.ssrfProtection,
|
|
140
|
+
});
|
|
141
|
+
if (!sanitizeResult.valid) {
|
|
142
|
+
const error = new Error(`URL validation failed: ${sanitizeResult.error}`);
|
|
143
|
+
this.logger.error(`URL validation failed for ${fullURL}: ${sanitizeResult.error}`);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
// 如果URL被修改,更新配置
|
|
147
|
+
if (sanitizeResult.url !== fullURL) {
|
|
148
|
+
// 更新URL为清洗后的安全URL
|
|
149
|
+
this.logger.debug(`URL sanitized from "${fullURL}" to "${sanitizeResult.url}"`);
|
|
150
|
+
// 如果原始URL是相对路径,保持相对路径;否则更新为清洗后的完整URL
|
|
151
|
+
if (requestURL && !requestURL.startsWith('http://') && !requestURL.startsWith('https://')) {
|
|
152
|
+
// 相对路径情况:从清洗后的完整URL中提取相对路径部分
|
|
153
|
+
try {
|
|
154
|
+
const sanitizedURL = new URL(sanitizeResult.url);
|
|
155
|
+
const baseURLParts = baseURL.split('/');
|
|
156
|
+
const sanitizedPathParts = sanitizedURL.pathname.split('/');
|
|
157
|
+
// 计算相对路径
|
|
158
|
+
let relativePath = sanitizedURL.pathname;
|
|
159
|
+
if (baseURLParts.length > 3) {
|
|
160
|
+
const basePath = baseURLParts.slice(3).join('/');
|
|
161
|
+
if (relativePath.startsWith(basePath)) {
|
|
162
|
+
relativePath = relativePath.substring(basePath.length);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
config.url = relativePath || requestURL;
|
|
166
|
+
}
|
|
167
|
+
catch (_p) {
|
|
168
|
+
// 如果提取失败,保持原始URL
|
|
169
|
+
config.url = requestURL;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
// 绝对路径情况:直接使用清洗后的URL
|
|
174
|
+
config.url = sanitizeResult.url;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// ========== 安全验证结束 ==========
|
|
179
|
+
// Capture the calling context information
|
|
180
|
+
const callingContext = this.captureCallingContext();
|
|
63
181
|
const startTime = Date.now();
|
|
64
182
|
const retryRecorder = retry_recorder_util_1.RetryRecorder.create();
|
|
65
183
|
let requestId;
|
|
66
184
|
let circuitBreakerState;
|
|
67
|
-
let cacheHit = false;
|
|
68
185
|
try {
|
|
186
|
+
// 应用认证配置
|
|
187
|
+
const authConfig = yield this.applyAuthToConfig(config);
|
|
69
188
|
// 应用装饰器配置
|
|
70
|
-
const enhancedConfig = this.applyDecoratorConfig(
|
|
189
|
+
const enhancedConfig = this.applyDecoratorConfig(authConfig, decoratorContext);
|
|
190
|
+
// 将 retryRecorder 存储到 config metadata 中,供 onRetry 回调使用
|
|
191
|
+
enhancedConfig.metadata = enhancedConfig.metadata || {};
|
|
192
|
+
enhancedConfig.metadata.retryRecorder = retryRecorder;
|
|
71
193
|
// 获取装饰器配置
|
|
72
|
-
const decoratorConfigs =
|
|
73
|
-
? decorators_1.HttpDecoratorUtils.getAllDecoratorConfigs(
|
|
194
|
+
const decoratorConfigs = effectiveDecoratorContext
|
|
195
|
+
? decorators_1.HttpDecoratorUtils.getAllDecoratorConfigs(effectiveDecoratorContext.target, effectiveDecoratorContext.propertyKey)
|
|
74
196
|
: {};
|
|
197
|
+
// 存储装饰器的重试配置到 metadata,供 retryCondition 使用
|
|
198
|
+
if (((_c = decoratorConfigs.retry) === null || _c === void 0 ? void 0 : _c.enabled) !== undefined) {
|
|
199
|
+
enhancedConfig.metadata.retryEnabled = decoratorConfigs.retry.enabled;
|
|
200
|
+
}
|
|
75
201
|
// 日志记录开始
|
|
76
|
-
const
|
|
202
|
+
const decoratorLogging = decoratorConfigs.logging || {};
|
|
203
|
+
this.logger.debug(`Logging config merge: decoratorLogging=${JSON.stringify(decoratorLogging)}, defaultLogging=${JSON.stringify(this.defaultConfig.logging)}`);
|
|
204
|
+
const loggingOptions = Object.assign(Object.assign(Object.assign({}, this.defaultConfig.logging), decoratorLogging), { databaseLogging: (_d = this.defaultConfig.logging) === null || _d === void 0 ? void 0 : _d.databaseLogging });
|
|
205
|
+
this.logger.debug(`Merged loggingOptions: databaseLog=${loggingOptions.databaseLog}, hasDatabaseLogging=${!!loggingOptions.databaseLogging}`);
|
|
77
206
|
if (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.enabled) {
|
|
78
207
|
requestId = this.loggingService.logRequestStart(enhancedConfig, loggingOptions);
|
|
79
208
|
// 将requestId保存到config中
|
|
80
209
|
enhancedConfig.metadata = enhancedConfig.metadata || {};
|
|
81
210
|
enhancedConfig.metadata.requestId = requestId;
|
|
82
211
|
}
|
|
83
|
-
// 缓存检查
|
|
84
|
-
const cacheConfig = decoratorConfigs.cache || this.defaultConfig.cache;
|
|
85
|
-
if ((cacheConfig === null || cacheConfig === void 0 ? void 0 : cacheConfig.enabled) &&
|
|
86
|
-
this.shouldCacheRequest(enhancedConfig, cacheConfig)) {
|
|
87
|
-
const cachedResponse = yield this.cacheService.get(enhancedConfig, cacheConfig);
|
|
88
|
-
if (cachedResponse) {
|
|
89
|
-
cacheHit = true;
|
|
90
|
-
if (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.enabled) {
|
|
91
|
-
const databaseLogging = (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.databaseLog) ||
|
|
92
|
-
((_b = (_a = this.defaultConfig.logging) === null || _a === void 0 ? void 0 : _a.databaseLogging) === null || _b === void 0 ? void 0 : _b.enabled);
|
|
93
|
-
this.loggingService.logRequestSuccess(cachedResponse, startTime, requestId, loggingOptions, databaseLogging, undefined, // no retry records for cache hit
|
|
94
|
-
cacheHit, undefined, // circuit breaker state
|
|
95
|
-
decoratorContext);
|
|
96
|
-
}
|
|
97
|
-
return cachedResponse.data;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
212
|
// 应用超时配置
|
|
101
213
|
const timeout = decoratorConfigs.timeout || this.defaultConfig.timeout;
|
|
102
214
|
if (timeout) {
|
|
@@ -105,53 +217,60 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
105
217
|
// 应用代理配置
|
|
106
218
|
const proxyConfig = decoratorConfigs.proxy || this.defaultConfig.proxy;
|
|
107
219
|
if (proxyConfig === null || proxyConfig === void 0 ? void 0 : proxyConfig.enabled) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
auth: proxyConfig.auth,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
// 配置axios-retry的onRetry回调以记录重试
|
|
116
|
-
if ((_c = this.defaultConfig.retry) === null || _c === void 0 ? void 0 : _c.enabled) {
|
|
117
|
-
const originalOnRetry = this.defaultConfig.retry.onRetry;
|
|
118
|
-
this.defaultConfig.retry.onRetry = (retryCount, error, requestConfig) => {
|
|
119
|
-
// 记录重试
|
|
120
|
-
const retryRecord = retry_recorder_util_1.RetryRecorder.recordRetry(retryCount, error, requestConfig, this.calculateRetryDelay(retryCount, this.defaultConfig.retry));
|
|
121
|
-
retryRecorder.addRecord(retryRecord);
|
|
122
|
-
// 调用原始回调
|
|
123
|
-
if (originalOnRetry) {
|
|
124
|
-
originalOnRetry(retryCount, error, requestConfig);
|
|
125
|
-
}
|
|
126
|
-
};
|
|
220
|
+
const resolvedProxy = this.resolveProxyConfig(proxyConfig, enhancedConfig.url);
|
|
221
|
+
if (resolvedProxy !== false) {
|
|
222
|
+
enhancedConfig.proxy = resolvedProxy;
|
|
223
|
+
}
|
|
127
224
|
}
|
|
128
225
|
// 执行请求(带重试和熔断器)
|
|
129
|
-
const response = yield this.executeWithFeatures(enhancedConfig, decoratorConfigs, requestId, startTime, retryRecorder
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if ((cacheConfig === null || cacheConfig === void 0 ? void 0 : cacheConfig.enabled) &&
|
|
134
|
-
this.shouldCacheRequest(enhancedConfig, cacheConfig)) {
|
|
135
|
-
yield this.cacheService.set(enhancedConfig, response, cacheConfig);
|
|
136
|
-
}
|
|
226
|
+
const { response, circuitBreakerState: state } = yield this.executeWithFeatures(enhancedConfig, decoratorConfigs, requestId, startTime, retryRecorder);
|
|
227
|
+
// 更新 circuitBreakerState 变量
|
|
228
|
+
circuitBreakerState = state;
|
|
229
|
+
this.logger.debug(`Request completed, circuitBreakerState: ${circuitBreakerState || 'undefined'}`);
|
|
137
230
|
// 成功日志
|
|
138
231
|
if (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.enabled) {
|
|
139
|
-
const databaseLogging = (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.
|
|
140
|
-
((
|
|
141
|
-
this.
|
|
232
|
+
const databaseLogging = (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.databaseLogging) ||
|
|
233
|
+
((_f = (_e = this.defaultConfig.logging) === null || _e === void 0 ? void 0 : _e.databaseLogging) === null || _f === void 0 ? void 0 : _f.enabled);
|
|
234
|
+
this.logger.debug(`Logging request success with circuitBreakerState: ${circuitBreakerState || 'undefined'}`);
|
|
235
|
+
this.loggingService.logRequestSuccess(response, startTime, requestId, loggingOptions, databaseLogging, retryRecorder.getRecords(), circuitBreakerState, decoratorContext, effectiveClientName, callingContext);
|
|
236
|
+
}
|
|
237
|
+
// 更新统计信息
|
|
238
|
+
this.updateRequestStats(true, Date.now() - startTime, ((_g = response.config) === null || _g === void 0 ? void 0 : _g.method) || 'GET', response.status);
|
|
239
|
+
// 根据返回选项处理响应
|
|
240
|
+
const options = returnOptions || { returnType: 'data' };
|
|
241
|
+
switch (options.returnType) {
|
|
242
|
+
case 'full':
|
|
243
|
+
// 返回完整响应对象
|
|
244
|
+
return response;
|
|
245
|
+
case 'custom':
|
|
246
|
+
// 使用自定义转换函数
|
|
247
|
+
if (options.transform) {
|
|
248
|
+
return options.transform(response);
|
|
249
|
+
}
|
|
250
|
+
// 如果没有提供转换函数,回退到返回data
|
|
251
|
+
return response.data;
|
|
252
|
+
case 'data':
|
|
253
|
+
default:
|
|
254
|
+
// 默认只返回data(保持向后兼容)
|
|
255
|
+
return response.data;
|
|
142
256
|
}
|
|
143
|
-
return response.data;
|
|
144
257
|
}
|
|
145
258
|
catch (error) {
|
|
146
259
|
// 错误日志
|
|
147
|
-
const
|
|
148
|
-
? decorators_1.HttpDecoratorUtils.getLoggingOptions(
|
|
149
|
-
:
|
|
260
|
+
const decoratorLogging = effectiveDecoratorContext
|
|
261
|
+
? decorators_1.HttpDecoratorUtils.getLoggingOptions(effectiveDecoratorContext.target, effectiveDecoratorContext.propertyKey)
|
|
262
|
+
: {};
|
|
263
|
+
const loggingOptions = Object.assign(Object.assign(Object.assign({}, this.defaultConfig.logging), decoratorLogging), { databaseLogging: (_h = this.defaultConfig.logging) === null || _h === void 0 ? void 0 : _h.databaseLogging });
|
|
150
264
|
if (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.enabled) {
|
|
151
265
|
const databaseLogging = (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.databaseLog) ||
|
|
152
|
-
((
|
|
153
|
-
|
|
266
|
+
((_k = (_j = this.defaultConfig.logging) === null || _j === void 0 ? void 0 : _j.databaseLogging) === null || _k === void 0 ? void 0 : _k.enabled);
|
|
267
|
+
const records = retryRecorder.getRecords();
|
|
268
|
+
this.loggingService.logRequestError(error, startTime, requestId, (records === null || records === void 0 ? void 0 : records.length) ? Math.max(...records.map((r) => r.attempt)) + 1 : 1, loggingOptions, databaseLogging, records, circuitBreakerState, effectiveDecoratorContext, effectiveClientName, callingContext);
|
|
154
269
|
}
|
|
270
|
+
// 更新统计信息
|
|
271
|
+
const errorMethod = (_l = error.config) === null || _l === void 0 ? void 0 : _l.method;
|
|
272
|
+
const errorStatus = (_m = error.response) === null || _m === void 0 ? void 0 : _m.status;
|
|
273
|
+
this.updateRequestStats(false, Date.now() - startTime, errorMethod, errorStatus);
|
|
155
274
|
throw error;
|
|
156
275
|
}
|
|
157
276
|
});
|
|
@@ -172,14 +291,21 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
172
291
|
* 获取请求统计信息
|
|
173
292
|
*/
|
|
174
293
|
getStats() {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
:
|
|
178
|
-
|
|
294
|
+
return {
|
|
295
|
+
totalRequests: this.requestStats.totalRequests,
|
|
296
|
+
successfulRequests: this.requestStats.successfulRequests,
|
|
297
|
+
failedRequests: this.requestStats.failedRequests,
|
|
298
|
+
totalResponseTime: this.requestStats.totalResponseTime,
|
|
299
|
+
averageResponseTime: this.requestStats.averageResponseTime,
|
|
300
|
+
successRate: this.requestStats.totalRequests > 0
|
|
179
301
|
? (this.requestStats.successfulRequests /
|
|
180
302
|
this.requestStats.totalRequests) *
|
|
181
303
|
100
|
|
182
|
-
: 0,
|
|
304
|
+
: 0,
|
|
305
|
+
requestsByMethod: this.requestStats.requestsByMethod,
|
|
306
|
+
requestsByStatus: this.requestStats.requestsByStatus,
|
|
307
|
+
circuitBreakerStats: this.circuitBreakerService.getAllStates(),
|
|
308
|
+
};
|
|
183
309
|
}
|
|
184
310
|
/**
|
|
185
311
|
* 重置统计信息
|
|
@@ -190,34 +316,41 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
190
316
|
successfulRequests: 0,
|
|
191
317
|
failedRequests: 0,
|
|
192
318
|
totalResponseTime: 0,
|
|
319
|
+
averageResponseTime: 0,
|
|
193
320
|
requestsByMethod: {},
|
|
194
321
|
requestsByStatus: {},
|
|
195
322
|
};
|
|
196
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* 获取客户端名称
|
|
326
|
+
*/
|
|
327
|
+
getName() {
|
|
328
|
+
return this.clientName;
|
|
329
|
+
}
|
|
197
330
|
// 便捷方法
|
|
198
|
-
get(url, config) {
|
|
331
|
+
get(url, config, clientName, returnOptions) {
|
|
199
332
|
return __awaiter(this, void 0, void 0, function* () {
|
|
200
|
-
return this.request(Object.assign(Object.assign({}, config), { method: 'GET', url }));
|
|
333
|
+
return this.request(Object.assign(Object.assign({}, config), { method: 'GET', url }), undefined, clientName, returnOptions);
|
|
201
334
|
});
|
|
202
335
|
}
|
|
203
|
-
post(url, data, config) {
|
|
336
|
+
post(url, data, config, clientName, returnOptions) {
|
|
204
337
|
return __awaiter(this, void 0, void 0, function* () {
|
|
205
|
-
return this.request(Object.assign(Object.assign({}, config), { method: 'POST', url, data }));
|
|
338
|
+
return this.request(Object.assign(Object.assign({}, config), { method: 'POST', url, data }), undefined, clientName, returnOptions);
|
|
206
339
|
});
|
|
207
340
|
}
|
|
208
|
-
put(url, data, config) {
|
|
341
|
+
put(url, data, config, clientName, returnOptions) {
|
|
209
342
|
return __awaiter(this, void 0, void 0, function* () {
|
|
210
|
-
return this.request(Object.assign(Object.assign({}, config), { method: 'PUT', url, data }));
|
|
343
|
+
return this.request(Object.assign(Object.assign({}, config), { method: 'PUT', url, data }), undefined, clientName, returnOptions);
|
|
211
344
|
});
|
|
212
345
|
}
|
|
213
|
-
patch(url, data, config) {
|
|
346
|
+
patch(url, data, config, clientName, returnOptions) {
|
|
214
347
|
return __awaiter(this, void 0, void 0, function* () {
|
|
215
|
-
return this.request(Object.assign(Object.assign({}, config), { method: 'PATCH', url, data }));
|
|
348
|
+
return this.request(Object.assign(Object.assign({}, config), { method: 'PATCH', url, data }), undefined, clientName, returnOptions);
|
|
216
349
|
});
|
|
217
350
|
}
|
|
218
|
-
delete(url, config) {
|
|
351
|
+
delete(url, config, clientName, returnOptions) {
|
|
219
352
|
return __awaiter(this, void 0, void 0, function* () {
|
|
220
|
-
return this.request(Object.assign(Object.assign({}, config), { method: 'DELETE', url }));
|
|
353
|
+
return this.request(Object.assign(Object.assign({}, config), { method: 'DELETE', url }), undefined, clientName, returnOptions);
|
|
221
354
|
});
|
|
222
355
|
}
|
|
223
356
|
/**
|
|
@@ -229,11 +362,12 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
229
362
|
* @param options 等待锁选项
|
|
230
363
|
* @returns 响应数据
|
|
231
364
|
*/
|
|
232
|
-
authRequest(config, tokenProvider, options) {
|
|
365
|
+
authRequest(config, tokenProvider, options, clientName, returnOptions) {
|
|
233
366
|
return __awaiter(this, void 0, void 0, function* () {
|
|
367
|
+
const effectiveClientName = clientName || this.clientName;
|
|
234
368
|
if (!this.redisLockService) {
|
|
235
369
|
this.logger.warn('RedisLockService not available, proceeding without lock');
|
|
236
|
-
return this.request(config);
|
|
370
|
+
return this.request(config, undefined, effectiveClientName, returnOptions);
|
|
237
371
|
}
|
|
238
372
|
const { lockKey = `auth-request:${(0, request_id_util_1.generateRequestId)()}`, lockTimeout = 30000, waitTimeout = 60000, enableRetry = true, } = options || {};
|
|
239
373
|
try {
|
|
@@ -244,7 +378,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
244
378
|
// 添加认证头
|
|
245
379
|
const authConfig = Object.assign(Object.assign({}, config), { headers: Object.assign(Object.assign({}, config.headers), { Authorization: `Bearer ${token}` }) });
|
|
246
380
|
// 执行请求
|
|
247
|
-
return this.request(authConfig);
|
|
381
|
+
return this.request(authConfig, undefined, effectiveClientName, returnOptions);
|
|
248
382
|
}), {
|
|
249
383
|
ttl: lockTimeout,
|
|
250
384
|
retryCount: enableRetry ? 3 : 0,
|
|
@@ -263,7 +397,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
263
397
|
this.logger.warn('Retrying auth request without lock');
|
|
264
398
|
const token = yield tokenProvider();
|
|
265
399
|
const authConfig = Object.assign(Object.assign({}, config), { headers: Object.assign(Object.assign({}, config.headers), { Authorization: `Bearer ${token}` }) });
|
|
266
|
-
return this.request(authConfig);
|
|
400
|
+
return this.request(authConfig, undefined, effectiveClientName);
|
|
267
401
|
}
|
|
268
402
|
throw error;
|
|
269
403
|
}
|
|
@@ -278,8 +412,9 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
278
412
|
* @param options 等待锁选项
|
|
279
413
|
* @returns 响应数组
|
|
280
414
|
*/
|
|
281
|
-
authBatchRequest(requests, tokenProvider, options) {
|
|
415
|
+
authBatchRequest(requests, tokenProvider, options, clientName) {
|
|
282
416
|
return __awaiter(this, void 0, void 0, function* () {
|
|
417
|
+
const effectiveClientName = clientName || this.clientName;
|
|
283
418
|
if (!this.redisLockService) {
|
|
284
419
|
this.logger.warn('RedisLockService not available, proceeding batch auth requests without lock');
|
|
285
420
|
// 无锁批量执行
|
|
@@ -287,7 +422,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
287
422
|
const promises = requests.map((request) => __awaiter(this, void 0, void 0, function* () {
|
|
288
423
|
try {
|
|
289
424
|
const authConfig = Object.assign(Object.assign({}, request.config), { headers: Object.assign(Object.assign({}, request.config.headers), { Authorization: `Bearer ${token}` }) });
|
|
290
|
-
return yield this.request(authConfig);
|
|
425
|
+
return yield this.request(authConfig, undefined, effectiveClientName);
|
|
291
426
|
}
|
|
292
427
|
catch (error) {
|
|
293
428
|
this.logger.error(`Batch auth request failed for key: ${request.key}`, error);
|
|
@@ -309,7 +444,7 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
309
444
|
const executeRequest = (requestConfig, key, index) => __awaiter(this, void 0, void 0, function* () {
|
|
310
445
|
try {
|
|
311
446
|
const authConfig = Object.assign(Object.assign({}, requestConfig), { headers: Object.assign(Object.assign({}, requestConfig.headers), { Authorization: `Bearer ${token}` }) });
|
|
312
|
-
const result = yield this.request(authConfig);
|
|
447
|
+
const result = yield this.request(authConfig, undefined, effectiveClientName);
|
|
313
448
|
results[index] = result;
|
|
314
449
|
return result;
|
|
315
450
|
}
|
|
@@ -365,42 +500,125 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
365
500
|
}
|
|
366
501
|
});
|
|
367
502
|
}
|
|
503
|
+
/**
|
|
504
|
+
* Capture calling context information
|
|
505
|
+
* @returns Calling context with service class and method name
|
|
506
|
+
*/
|
|
507
|
+
captureCallingContext() {
|
|
508
|
+
try {
|
|
509
|
+
// Use CallStackExtractor to get the calling context
|
|
510
|
+
const stackInfo = call_stack_extractor_util_1.CallStackExtractor.getCallInfo();
|
|
511
|
+
// Skip internal HTTP client calls
|
|
512
|
+
if (stackInfo.serviceClass && stackInfo.methodName) {
|
|
513
|
+
// Check if it's an internal call
|
|
514
|
+
const isInternal = call_stack_extractor_util_1.CallStackExtractor['isInternalCall'](stackInfo.serviceClass);
|
|
515
|
+
if (!isInternal) {
|
|
516
|
+
return {
|
|
517
|
+
serviceClass: stackInfo.serviceClass,
|
|
518
|
+
methodName: stackInfo.methodName,
|
|
519
|
+
operationName: stackInfo.operationName,
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
// If no useful context found, return empty
|
|
524
|
+
return {};
|
|
525
|
+
}
|
|
526
|
+
catch (error) {
|
|
527
|
+
this.logger.warn('Failed to capture calling context:', error.message);
|
|
528
|
+
return {};
|
|
529
|
+
}
|
|
530
|
+
}
|
|
368
531
|
/**
|
|
369
532
|
* 创建Axios实例并配置axios-retry
|
|
370
533
|
*/
|
|
371
534
|
createAxiosInstance() {
|
|
372
|
-
var _a, _b;
|
|
373
|
-
|
|
535
|
+
var _a, _b, _c;
|
|
536
|
+
// 合并代理配置和 axiosConfig 透传配置
|
|
537
|
+
const resolvedProxy = this.resolveProxyConfig(this.defaultConfig.proxy);
|
|
538
|
+
// 处理 SSL 配置和 httpsAgent
|
|
539
|
+
let httpsAgent = (_a = this.defaultConfig.axiosConfig) === null || _a === void 0 ? void 0 : _a.httpsAgent;
|
|
540
|
+
if ((_b = this.defaultConfig.axiosConfig) === null || _b === void 0 ? void 0 : _b.ssl) {
|
|
541
|
+
const ssl = this.defaultConfig.axiosConfig.ssl;
|
|
542
|
+
const https = require('https');
|
|
543
|
+
if (!httpsAgent) {
|
|
544
|
+
// 如果没有预定义的 httpsAgent,使用 SSL 配置创建
|
|
545
|
+
httpsAgent = new https.Agent(Object.assign(Object.assign({}, ssl), { keepAlive: true }));
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
// 如果同时提供了 httpsAgent 和 ssl 配置
|
|
549
|
+
// ssl 配置会覆盖 httpsAgent 的相关选项
|
|
550
|
+
this.logger.warn('Both httpsAgent and ssl config provided. SSL config will take precedence for certificate options.');
|
|
551
|
+
// 创建新的 Agent,合并原有配置和 SSL 配置
|
|
552
|
+
httpsAgent = new https.Agent(Object.assign({
|
|
553
|
+
// 保留原 Agent 的选项(除了证书相关)
|
|
554
|
+
keepAlive: true }, ssl));
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
// 构建 axios 创建配置
|
|
558
|
+
const axiosCreateConfig = {
|
|
374
559
|
baseURL: this.defaultConfig.baseURL,
|
|
375
560
|
timeout: this.defaultConfig.timeout,
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
protocol: this.defaultConfig.proxy.protocol,
|
|
381
|
-
auth: this.defaultConfig.proxy.auth,
|
|
382
|
-
}
|
|
561
|
+
// 只有当 resolvedProxy 是有效的配置对象时才设置代理
|
|
562
|
+
// false 和 undefined 都表示不使用代理
|
|
563
|
+
proxy: resolvedProxy && typeof resolvedProxy === 'object'
|
|
564
|
+
? resolvedProxy
|
|
383
565
|
: undefined,
|
|
384
|
-
|
|
566
|
+
// 应用处理后的 httpsAgent
|
|
567
|
+
httpsAgent: httpsAgent,
|
|
568
|
+
};
|
|
569
|
+
// 透传所有其他 axiosConfig 配置(排除已特殊处理的字段)
|
|
570
|
+
// 只在值有效时才覆盖
|
|
571
|
+
if (this.defaultConfig.axiosConfig) {
|
|
572
|
+
const _d = this.defaultConfig.axiosConfig, { ssl, httpsAgent: _ } = _d, restAxiosConfig = __rest(_d, ["ssl", "httpsAgent"]);
|
|
573
|
+
for (const key in restAxiosConfig) {
|
|
574
|
+
if (restAxiosConfig[key] !== undefined) {
|
|
575
|
+
axiosCreateConfig[key] = restAxiosConfig[key];
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
const instance = require('axios').create(axiosCreateConfig);
|
|
385
580
|
// 配置axios-retry
|
|
386
|
-
if ((
|
|
581
|
+
if ((_c = this.defaultConfig.retry) === null || _c === void 0 ? void 0 : _c.enabled) {
|
|
387
582
|
(0, axios_retry_1.default)(instance, {
|
|
388
583
|
retries: this.defaultConfig.retry.retries || 3,
|
|
389
584
|
retryDelay: this.defaultConfig.retry.retryDelay ||
|
|
390
585
|
((retryCount) => Math.pow(2, retryCount) * 1000),
|
|
391
586
|
retryCondition: this.defaultConfig.retry.retryCondition ||
|
|
392
587
|
((error) => {
|
|
588
|
+
var _a;
|
|
589
|
+
// 检查装饰器配置是否禁用了重试
|
|
590
|
+
const requestConfig = error.config;
|
|
591
|
+
if (((_a = requestConfig === null || requestConfig === void 0 ? void 0 : requestConfig.metadata) === null || _a === void 0 ? void 0 : _a.retryEnabled) === false) {
|
|
592
|
+
return false; // 装饰器明确禁用了重试
|
|
593
|
+
}
|
|
594
|
+
// 默认重试条件:网络错误、超时、5xx错误、429错误
|
|
393
595
|
if (!error.response)
|
|
394
596
|
return true; // 网络错误
|
|
395
597
|
const status = error.response.status;
|
|
396
598
|
return status >= 500 || status === 429; // 5xx错误或429限流
|
|
397
599
|
}),
|
|
398
600
|
shouldResetTimeout: this.defaultConfig.retry.shouldResetTimeout !== false,
|
|
399
|
-
onRetry:
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
601
|
+
onRetry: (retryCount, error, requestConfig) => {
|
|
602
|
+
var _a, _b, _c, _d;
|
|
603
|
+
// 从 request config metadata 中获取 retryRecorder
|
|
604
|
+
const retryRecorder = (_a = requestConfig.metadata) === null || _a === void 0 ? void 0 : _a.retryRecorder;
|
|
605
|
+
if (retryRecorder) {
|
|
606
|
+
this.logger.debug(`Recording retry attempt ${retryCount} for ${(_b = requestConfig.method) === null || _b === void 0 ? void 0 : _b.toUpperCase()} ${requestConfig.url}`);
|
|
607
|
+
const retryRecord = retry_recorder_util_1.RetryRecorder.recordRetry(retryCount, error, requestConfig, this.calculateRetryDelay(retryCount, this.defaultConfig.retry));
|
|
608
|
+
retryRecorder.addRecord(retryRecord);
|
|
609
|
+
}
|
|
610
|
+
else {
|
|
611
|
+
this.logger.warn(`RetryRecorder not found in request config metadata for ${(_c = requestConfig.method) === null || _c === void 0 ? void 0 : _c.toUpperCase()} ${requestConfig.url}. Retry records will not be saved.`);
|
|
612
|
+
}
|
|
613
|
+
// 调用用户自定义的 onRetry 回调
|
|
614
|
+
if (this.defaultConfig.retry.onRetry) {
|
|
615
|
+
this.defaultConfig.retry.onRetry(retryCount, error, requestConfig);
|
|
616
|
+
}
|
|
617
|
+
else {
|
|
618
|
+
// 默认日志
|
|
619
|
+
this.logger.warn(`Retrying request (attempt ${retryCount}): ${(_d = requestConfig.method) === null || _d === void 0 ? void 0 : _d.toUpperCase()} ${requestConfig.url}`);
|
|
620
|
+
}
|
|
621
|
+
},
|
|
404
622
|
});
|
|
405
623
|
}
|
|
406
624
|
// 设置请求拦截器
|
|
@@ -413,7 +631,8 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
413
631
|
if (context.userId) {
|
|
414
632
|
config.headers['X-User-ID'] = context.userId;
|
|
415
633
|
}
|
|
416
|
-
// 存储requestId到config中供后续使用
|
|
634
|
+
// 存储requestId到config metadata中供后续使用
|
|
635
|
+
// 注意:不要覆盖已存在的 metadata,保留 retryRecorder 等其他数据
|
|
417
636
|
config.metadata = config.metadata || {};
|
|
418
637
|
config.metadata.requestId = requestId;
|
|
419
638
|
return config;
|
|
@@ -422,17 +641,19 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
422
641
|
return Promise.reject(error);
|
|
423
642
|
});
|
|
424
643
|
// 设置响应拦截器
|
|
644
|
+
// 注意: 统计信息已移至 request() 方法中统一管理,避免双重计数
|
|
425
645
|
instance.interceptors.response.use((response) => {
|
|
426
|
-
|
|
646
|
+
// 不再在这里更新统计,由 request() 方法统一管理
|
|
427
647
|
return response;
|
|
428
648
|
}, (error) => {
|
|
429
|
-
|
|
649
|
+
// 不再在这里更新统计,由 request() 方法统一管理
|
|
430
650
|
return Promise.reject(error);
|
|
431
651
|
});
|
|
432
652
|
return instance;
|
|
433
653
|
}
|
|
434
654
|
/**
|
|
435
655
|
* 执行带特性的请求(重试、熔断器等)
|
|
656
|
+
* 返回响应和熔断器状态
|
|
436
657
|
*/
|
|
437
658
|
executeWithFeatures(config, decoratorConfigs, requestId, startTime, retryRecorder, onCircuitBreakerStateChange) {
|
|
438
659
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -441,10 +662,17 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
441
662
|
const circuitBreakerConfig = decoratorConfigs.circuitBreaker || this.defaultConfig.circuitBreaker;
|
|
442
663
|
if (circuitBreakerConfig === null || circuitBreakerConfig === void 0 ? void 0 : circuitBreakerConfig.enabled) {
|
|
443
664
|
const circuitBreakerKey = this.generateCircuitBreakerKey(config);
|
|
444
|
-
|
|
665
|
+
this.logger.debug(`Circuit breaker key: ${circuitBreakerKey}`);
|
|
666
|
+
// 执行请求
|
|
667
|
+
const result = yield this.circuitBreakerService.executeWithCircuitBreaker(circuitBreakerKey, requestFn, circuitBreakerConfig, onCircuitBreakerStateChange);
|
|
668
|
+
// 请求完成后,主动获取当前熔断器状态
|
|
669
|
+
const currentState = this.circuitBreakerService.getCircuitBreakerState(circuitBreakerKey);
|
|
670
|
+
this.logger.debug(`After request, circuit breaker state: ${currentState || 'undefined'}`);
|
|
671
|
+
return { response: result, circuitBreakerState: currentState };
|
|
445
672
|
}
|
|
446
673
|
else {
|
|
447
|
-
|
|
674
|
+
const result = yield requestFn();
|
|
675
|
+
return { response: result, circuitBreakerState: undefined };
|
|
448
676
|
}
|
|
449
677
|
});
|
|
450
678
|
}
|
|
@@ -460,67 +688,42 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
460
688
|
}
|
|
461
689
|
/**
|
|
462
690
|
* 应用装饰器配置
|
|
691
|
+
* 只在装饰器配置值有效时才覆盖请求配置
|
|
463
692
|
*/
|
|
464
693
|
applyDecoratorConfig(config, decoratorContext) {
|
|
465
694
|
if (!decoratorContext)
|
|
466
695
|
return Object.assign({}, config);
|
|
467
696
|
const httpClientConfig = decorators_1.HttpDecoratorUtils.getHttpClientOptions(decoratorContext.target);
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
return cacheConfig.cacheableMethods.includes(method || 'get');
|
|
697
|
+
// 只在值有效时才合并
|
|
698
|
+
const result = Object.assign({}, config);
|
|
699
|
+
for (const key in httpClientConfig) {
|
|
700
|
+
if (httpClientConfig[key] !== undefined) {
|
|
701
|
+
result[key] = httpClientConfig[key];
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return result;
|
|
477
705
|
}
|
|
706
|
+
// Note: applyDecoratorConfig is not currently being called in executeWithFeatures
|
|
707
|
+
// The decorator config is already being applied via effectiveDecoratorContext
|
|
478
708
|
/**
|
|
479
709
|
* 生成熔断器键
|
|
480
710
|
*/
|
|
481
711
|
generateCircuitBreakerKey(config) {
|
|
482
712
|
var _a;
|
|
483
713
|
const method = ((_a = config.method) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || 'UNKNOWN';
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
* 更新请求统计
|
|
489
|
-
*/
|
|
490
|
-
updateStats(response) {
|
|
491
|
-
var _a, _b;
|
|
492
|
-
this.requestStats.totalRequests++;
|
|
493
|
-
this.requestStats.successfulRequests++;
|
|
494
|
-
const method = ((_a = response.config.method) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || 'UNKNOWN';
|
|
495
|
-
const status = response.status;
|
|
496
|
-
this.requestStats.requestsByMethod[method] =
|
|
497
|
-
(this.requestStats.requestsByMethod[method] || 0) + 1;
|
|
498
|
-
this.requestStats.requestsByStatus[status] =
|
|
499
|
-
(this.requestStats.requestsByStatus[status] || 0) + 1;
|
|
500
|
-
if ((_b = response.config.metadata) === null || _b === void 0 ? void 0 : _b.startTime) {
|
|
501
|
-
const responseTime = Date.now() -
|
|
502
|
-
response.config.metadata
|
|
503
|
-
.startTime;
|
|
504
|
-
this.requestStats.totalResponseTime += responseTime;
|
|
714
|
+
let url;
|
|
715
|
+
try {
|
|
716
|
+
// Try to construct URL with proper base
|
|
717
|
+
url = new URL(config.url || '', this.defaultConfig.baseURL || 'http://localhost');
|
|
505
718
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
this.requestStats.totalRequests++;
|
|
513
|
-
this.requestStats.failedRequests++;
|
|
514
|
-
if (error.config) {
|
|
515
|
-
const method = ((_a = error.config.method) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || 'UNKNOWN';
|
|
516
|
-
this.requestStats.requestsByMethod[method] =
|
|
517
|
-
(this.requestStats.requestsByMethod[method] || 0) + 1;
|
|
518
|
-
if (error.response) {
|
|
519
|
-
const status = error.response.status;
|
|
520
|
-
this.requestStats.requestsByStatus[status] =
|
|
521
|
-
(this.requestStats.requestsByStatus[status] || 0) + 1;
|
|
522
|
-
}
|
|
719
|
+
catch (error) {
|
|
720
|
+
// If URL construction fails, fall back to simple string format
|
|
721
|
+
this.logger.warn(`Failed to construct URL for circuit breaker key: ${config.url}, using fallback format`);
|
|
722
|
+
const baseURL = this.defaultConfig.baseURL || 'http://localhost';
|
|
723
|
+
const urlPath = config.url || '/';
|
|
724
|
+
return `${method}:${baseURL}${urlPath}`;
|
|
523
725
|
}
|
|
726
|
+
return `${method}:${url.host}${url.pathname}`;
|
|
524
727
|
}
|
|
525
728
|
/**
|
|
526
729
|
* 合并默认配置
|
|
@@ -549,15 +752,6 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
549
752
|
minimumThroughputThreshold: 10,
|
|
550
753
|
countHalfOpenCalls: true,
|
|
551
754
|
},
|
|
552
|
-
cache: {
|
|
553
|
-
enabled: true,
|
|
554
|
-
defaultTtl: 300000, // 5分钟
|
|
555
|
-
cacheableMethods: ['get'],
|
|
556
|
-
cacheableStatusCodes: [200, 201, 202, 204, 301, 302, 304],
|
|
557
|
-
options: {
|
|
558
|
-
layers: [cache_1.CacheLayer.MEMORY, cache_1.CacheLayer.REDIS],
|
|
559
|
-
},
|
|
560
|
-
},
|
|
561
755
|
logging: {
|
|
562
756
|
enabled: true,
|
|
563
757
|
logRequests: true,
|
|
@@ -566,12 +760,11 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
566
760
|
logHeaders: true,
|
|
567
761
|
logBody: true,
|
|
568
762
|
maxBodyLength: 1000,
|
|
569
|
-
|
|
763
|
+
sanitize: ['password', 'secret', 'token', 'apiKey', 'authorization', 'cookie'],
|
|
570
764
|
logLevel: 'info',
|
|
571
765
|
databaseLogging: {
|
|
572
|
-
enabled:
|
|
766
|
+
enabled: true,
|
|
573
767
|
dataSource: 'default',
|
|
574
|
-
tableName: 'http_logs',
|
|
575
768
|
},
|
|
576
769
|
},
|
|
577
770
|
};
|
|
@@ -579,10 +772,15 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
579
772
|
}
|
|
580
773
|
/**
|
|
581
774
|
* 深度合并对象
|
|
775
|
+
* 只在源值有效(非 undefined)时才覆盖目标值
|
|
582
776
|
*/
|
|
583
777
|
deepMerge(target, source) {
|
|
584
778
|
const result = Object.assign({}, target);
|
|
585
779
|
for (const key in source) {
|
|
780
|
+
// 跳过 undefined 值,不覆盖目标值
|
|
781
|
+
if (source[key] === undefined) {
|
|
782
|
+
continue;
|
|
783
|
+
}
|
|
586
784
|
if (source[key] &&
|
|
587
785
|
typeof source[key] === 'object' &&
|
|
588
786
|
!Array.isArray(source[key])) {
|
|
@@ -594,12 +792,158 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
594
792
|
}
|
|
595
793
|
return result;
|
|
596
794
|
}
|
|
795
|
+
/**
|
|
796
|
+
* 解析代理配置
|
|
797
|
+
* 支持从环境变量或手动配置中读取
|
|
798
|
+
* @param proxyConfig 代理配置
|
|
799
|
+
* @param targetUrl 目标 URL(用于 NO_PROXY 检查)
|
|
800
|
+
* @returns 解析后的代理配置,如果不应使用代理则返回 false 或 undefined
|
|
801
|
+
*/
|
|
802
|
+
resolveProxyConfig(proxyConfig, targetUrl) {
|
|
803
|
+
var _a, _b, _c, _d;
|
|
804
|
+
if (!(proxyConfig === null || proxyConfig === void 0 ? void 0 : proxyConfig.enabled)) {
|
|
805
|
+
return undefined;
|
|
806
|
+
}
|
|
807
|
+
// 如果启用从环境变量读取
|
|
808
|
+
if (proxyConfig.fromEnvironment) {
|
|
809
|
+
// 确定目标协议
|
|
810
|
+
let protocol = 'http';
|
|
811
|
+
if (targetUrl) {
|
|
812
|
+
try {
|
|
813
|
+
const url = new URL(targetUrl, this.defaultConfig.baseURL);
|
|
814
|
+
protocol = url.protocol === 'https:' ? 'https' : 'http';
|
|
815
|
+
}
|
|
816
|
+
catch (error) {
|
|
817
|
+
this.logger.warn(`Failed to parse target URL: ${error.message}`);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
// 从环境变量解析
|
|
821
|
+
const fullUrl = targetUrl
|
|
822
|
+
? new URL(targetUrl, this.defaultConfig.baseURL).href
|
|
823
|
+
: undefined;
|
|
824
|
+
const envProxy = proxy_environment_util_1.ProxyEnvironmentParser.parseFromEnvironment(protocol, fullUrl);
|
|
825
|
+
if (envProxy === false) {
|
|
826
|
+
this.logger.debug('Proxy bypassed based on environment configuration');
|
|
827
|
+
return false;
|
|
828
|
+
}
|
|
829
|
+
const result = {
|
|
830
|
+
host: envProxy.host,
|
|
831
|
+
port: envProxy.port,
|
|
832
|
+
protocol: envProxy.protocol,
|
|
833
|
+
};
|
|
834
|
+
// 只有当 auth 存在且包含有效值时才添加
|
|
835
|
+
if (((_a = envProxy.auth) === null || _a === void 0 ? void 0 : _a.username) && ((_b = envProxy.auth) === null || _b === void 0 ? void 0 : _b.password)) {
|
|
836
|
+
result.auth = {
|
|
837
|
+
username: envProxy.auth.username,
|
|
838
|
+
password: envProxy.auth.password,
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
return result;
|
|
842
|
+
}
|
|
843
|
+
// 使用手动配置
|
|
844
|
+
if (proxyConfig.host && proxyConfig.port) {
|
|
845
|
+
const result = {
|
|
846
|
+
host: proxyConfig.host,
|
|
847
|
+
port: proxyConfig.port,
|
|
848
|
+
protocol: proxyConfig.protocol,
|
|
849
|
+
};
|
|
850
|
+
// 只有当 auth 存在且包含有效值时才添加
|
|
851
|
+
if (((_c = proxyConfig.auth) === null || _c === void 0 ? void 0 : _c.username) && ((_d = proxyConfig.auth) === null || _d === void 0 ? void 0 : _d.password)) {
|
|
852
|
+
result.auth = {
|
|
853
|
+
username: proxyConfig.auth.username,
|
|
854
|
+
password: proxyConfig.auth.password,
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
return result;
|
|
858
|
+
}
|
|
859
|
+
this.logger.warn('Proxy is enabled but neither fromEnvironment nor manual configuration is provided');
|
|
860
|
+
return undefined;
|
|
861
|
+
}
|
|
862
|
+
/**
|
|
863
|
+
* 应用认证配置到请求配置
|
|
864
|
+
*/
|
|
865
|
+
applyAuthToConfig(config) {
|
|
866
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
867
|
+
if (!this.authConfig) {
|
|
868
|
+
return config;
|
|
869
|
+
}
|
|
870
|
+
// Create a new config object to avoid type issues
|
|
871
|
+
const authConfig = Object.assign({}, config);
|
|
872
|
+
switch (this.authConfig.type) {
|
|
873
|
+
case api_client_config_interface_1.AuthType.NONE:
|
|
874
|
+
break;
|
|
875
|
+
case api_client_config_interface_1.AuthType.API_KEY:
|
|
876
|
+
const apiKeyConfig = this.authConfig.config;
|
|
877
|
+
if (apiKeyConfig.location === 'header') {
|
|
878
|
+
const headerName = apiKeyConfig.name || 'X-API-Key';
|
|
879
|
+
const value = apiKeyConfig.prefix
|
|
880
|
+
? `${apiKeyConfig.prefix} ${apiKeyConfig.key}`
|
|
881
|
+
: apiKeyConfig.key;
|
|
882
|
+
authConfig.headers = Object.assign(Object.assign({}, authConfig.headers), { [headerName]: value });
|
|
883
|
+
}
|
|
884
|
+
else if (apiKeyConfig.location === 'query') {
|
|
885
|
+
const paramName = apiKeyConfig.name || 'api_key';
|
|
886
|
+
authConfig.params = Object.assign(Object.assign({}, authConfig.params), { [paramName]: apiKeyConfig.key });
|
|
887
|
+
}
|
|
888
|
+
break;
|
|
889
|
+
case api_client_config_interface_1.AuthType.BEARER_TOKEN:
|
|
890
|
+
const bearerConfig = this.authConfig.config;
|
|
891
|
+
const scheme = bearerConfig.scheme || 'Bearer';
|
|
892
|
+
authConfig.headers = Object.assign(Object.assign({}, authConfig.headers), { Authorization: `${scheme} ${bearerConfig.token}` });
|
|
893
|
+
break;
|
|
894
|
+
case api_client_config_interface_1.AuthType.BASIC_AUTH:
|
|
895
|
+
const basicConfig = this.authConfig.config;
|
|
896
|
+
const credentials = Buffer.from(`${basicConfig.username}:${basicConfig.password}`).toString('base64');
|
|
897
|
+
authConfig.headers = Object.assign(Object.assign({}, authConfig.headers), { Authorization: `Basic ${credentials}` });
|
|
898
|
+
break;
|
|
899
|
+
case api_client_config_interface_1.AuthType.OAUTH2:
|
|
900
|
+
const oauthConfig = this.authConfig.config;
|
|
901
|
+
// For now, using the access token directly if available
|
|
902
|
+
if (oauthConfig.accessToken) {
|
|
903
|
+
authConfig.headers = Object.assign(Object.assign({}, authConfig.headers), { Authorization: `Bearer ${oauthConfig.accessToken}` });
|
|
904
|
+
}
|
|
905
|
+
break;
|
|
906
|
+
case api_client_config_interface_1.AuthType.CUSTOM:
|
|
907
|
+
// Handle CUSTOM authentication which requires async processing
|
|
908
|
+
const customConfig = this.authConfig.config;
|
|
909
|
+
return yield customConfig.authenticator(authConfig);
|
|
910
|
+
}
|
|
911
|
+
return authConfig;
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
/**
|
|
915
|
+
* 更新请求统计信息
|
|
916
|
+
* 统一管理所有统计,避免在拦截器中重复统计
|
|
917
|
+
*/
|
|
918
|
+
updateRequestStats(success, responseTime, method, status) {
|
|
919
|
+
this.requestStats.totalRequests++;
|
|
920
|
+
if (success) {
|
|
921
|
+
this.requestStats.successfulRequests++;
|
|
922
|
+
}
|
|
923
|
+
else {
|
|
924
|
+
this.requestStats.failedRequests++;
|
|
925
|
+
}
|
|
926
|
+
this.requestStats.totalResponseTime += responseTime;
|
|
927
|
+
this.requestStats.averageResponseTime =
|
|
928
|
+
this.requestStats.totalResponseTime / this.requestStats.totalRequests;
|
|
929
|
+
// 统计方法分布
|
|
930
|
+
if (method) {
|
|
931
|
+
const normalizedMethod = method.toUpperCase();
|
|
932
|
+
this.requestStats.requestsByMethod[normalizedMethod] =
|
|
933
|
+
(this.requestStats.requestsByMethod[normalizedMethod] || 0) + 1;
|
|
934
|
+
}
|
|
935
|
+
// 统计状态码分布
|
|
936
|
+
if (status) {
|
|
937
|
+
this.requestStats.requestsByStatus[status] =
|
|
938
|
+
(this.requestStats.requestsByStatus[status] || 0) + 1;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
597
941
|
};
|
|
598
942
|
exports.HttpClientService = HttpClientService;
|
|
599
943
|
exports.HttpClientService = HttpClientService = HttpClientService_1 = __decorate([
|
|
600
944
|
(0, common_1.Injectable)(),
|
|
945
|
+
__param(2, (0, common_1.Optional)()),
|
|
601
946
|
__metadata("design:paramtypes", [circuit_breaker_service_1.HttpCircuitBreakerService,
|
|
602
947
|
logging_service_1.HttpLoggingService,
|
|
603
|
-
|
|
604
|
-
redis_lock_service_1.RedisLockService, Object])
|
|
948
|
+
redis_lock_service_1.RedisLockService, Object, String, Object])
|
|
605
949
|
], HttpClientService);
|