@nest-omni/core 4.1.3-25 → 4.1.3-26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cache/cache.service.d.ts +3 -1
- package/cache/cache.service.js +8 -8
- package/cache/decorators/cache-put.decorator.js +5 -4
- package/cache/dependencies/callback.dependency.js +9 -0
- package/cache/dependencies/tag.dependency.d.ts +1 -9
- package/cache/dependencies/tag.dependency.js +5 -14
- package/cache/providers/lrucache.provider.d.ts +1 -0
- package/cache/providers/lrucache.provider.js +6 -4
- package/cache/providers/redis-cache.provider.d.ts +1 -0
- package/cache/providers/redis-cache.provider.js +8 -6
- package/http-client/config/http-client.config.js +3 -1
- package/http-client/examples/axios-config-extended.example.js +1 -3
- package/http-client/examples/flexible-response-example.d.ts +28 -0
- package/http-client/examples/flexible-response-example.js +120 -0
- package/http-client/examples/ssl-certificate.example.d.ts +2 -2
- package/http-client/examples/ssl-certificate.example.js +18 -17
- package/http-client/services/api-client-registry.service.d.ts +6 -6
- package/http-client/services/api-client-registry.service.js +8 -8
- package/http-client/services/circuit-breaker.service.d.ts +9 -9
- package/http-client/services/circuit-breaker.service.js +24 -24
- package/http-client/services/http-client.service.d.ts +30 -13
- package/http-client/services/http-client.service.js +75 -46
- package/http-client/services/logging.service.d.ts +16 -16
- package/http-client/services/logging.service.js +46 -45
- package/http-client/utils/proxy-environment.util.d.ts +12 -12
- package/http-client/utils/proxy-environment.util.js +25 -19
- package/http-client/utils/security-validator.util.d.ts +19 -19
- package/http-client/utils/security-validator.util.js +66 -64
- package/package.json +1 -1
- package/vault/vault-config.service.js +1 -1
package/cache/cache.service.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CacheOptions, CacheStats } from './interfaces';
|
|
2
2
|
import { CacheLayer } from './interfaces';
|
|
3
3
|
import { ClsCacheProvider, LRUCacheProvider, RedisCacheProvider } from './providers';
|
|
4
|
+
import { CacheSerializationService } from './cache-serialization.service';
|
|
4
5
|
/**
|
|
5
6
|
* Unified cache service with three-tier architecture
|
|
6
7
|
*
|
|
@@ -16,10 +17,11 @@ export declare class CacheService {
|
|
|
16
17
|
private readonly redisProvider;
|
|
17
18
|
private readonly enableCompression;
|
|
18
19
|
private readonly compressionThreshold;
|
|
20
|
+
private readonly serializationService;
|
|
19
21
|
private readonly logger;
|
|
20
22
|
private readonly providers;
|
|
21
23
|
private readonly stats;
|
|
22
|
-
constructor(clsProvider: ClsCacheProvider, lruProvider: LRUCacheProvider, redisProvider: RedisCacheProvider, enableCompression?: boolean, compressionThreshold?: number);
|
|
24
|
+
constructor(clsProvider: ClsCacheProvider, lruProvider: LRUCacheProvider, redisProvider: RedisCacheProvider, enableCompression?: boolean, compressionThreshold?: number, serializationService?: CacheSerializationService);
|
|
23
25
|
/**
|
|
24
26
|
* Get or set cache value with factory function
|
|
25
27
|
*
|
package/cache/cache.service.js
CHANGED
|
@@ -40,12 +40,13 @@ const cache_constants_1 = require("./cache.constants");
|
|
|
40
40
|
* Supports automatic fallback, backfill, and dependency-based invalidation.
|
|
41
41
|
*/
|
|
42
42
|
let CacheService = CacheService_1 = class CacheService {
|
|
43
|
-
constructor(clsProvider, lruProvider, redisProvider, enableCompression = false, compressionThreshold = 1024) {
|
|
43
|
+
constructor(clsProvider, lruProvider, redisProvider, enableCompression = false, compressionThreshold = 1024, serializationService = new cache_serialization_service_1.CacheSerializationService()) {
|
|
44
44
|
this.clsProvider = clsProvider;
|
|
45
45
|
this.lruProvider = lruProvider;
|
|
46
46
|
this.redisProvider = redisProvider;
|
|
47
47
|
this.enableCompression = enableCompression;
|
|
48
48
|
this.compressionThreshold = compressionThreshold;
|
|
49
|
+
this.serializationService = serializationService;
|
|
49
50
|
this.logger = new common_1.Logger(CacheService_1.name);
|
|
50
51
|
this.providers = new Map();
|
|
51
52
|
this.stats = {
|
|
@@ -125,8 +126,7 @@ let CacheService = CacheService_1 = class CacheService {
|
|
|
125
126
|
if (value !== null) {
|
|
126
127
|
// Check if value is compressed and decompress if needed
|
|
127
128
|
if (this.enableCompression && Buffer.isBuffer(value)) {
|
|
128
|
-
const
|
|
129
|
-
const decompressed = yield serializationService.deserialize(value);
|
|
129
|
+
const decompressed = yield this.serializationService.deserialize(value);
|
|
130
130
|
value = decompressed.data;
|
|
131
131
|
}
|
|
132
132
|
// Cache hit
|
|
@@ -206,14 +206,14 @@ let CacheService = CacheService_1 = class CacheService {
|
|
|
206
206
|
return __awaiter(this, void 0, void 0, function* () {
|
|
207
207
|
this.stats.totalDeletes++;
|
|
208
208
|
const targetLayers = layers || this.getDefaultLayers();
|
|
209
|
-
const keys = Array.isArray(key) ? key : [key];
|
|
210
209
|
const promises = targetLayers.map((layer) => __awaiter(this, void 0, void 0, function* () {
|
|
211
210
|
const provider = this.providers.get(layer);
|
|
212
211
|
if (!provider) {
|
|
213
212
|
return;
|
|
214
213
|
}
|
|
215
214
|
try {
|
|
216
|
-
|
|
215
|
+
// Pass the key directly (string or array) to the provider
|
|
216
|
+
yield provider.delete(key);
|
|
217
217
|
}
|
|
218
218
|
catch (error) {
|
|
219
219
|
this.logger.warn(`Failed to delete from ${layer} cache: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -357,8 +357,7 @@ let CacheService = CacheService_1 = class CacheService {
|
|
|
357
357
|
value !== null &&
|
|
358
358
|
value !== undefined &&
|
|
359
359
|
JSON.stringify(value).length >= this.compressionThreshold) {
|
|
360
|
-
const
|
|
361
|
-
const compressed = yield serializationService.serialize(value, {
|
|
360
|
+
const compressed = yield this.serializationService.serialize(value, {
|
|
362
361
|
compress: true,
|
|
363
362
|
compressThreshold: this.compressionThreshold,
|
|
364
363
|
});
|
|
@@ -471,7 +470,8 @@ exports.CacheService = CacheService = CacheService_1 = __decorate([
|
|
|
471
470
|
__param(3, (0, common_1.Inject)(cache_constants_1.CACHE_COMPRESSION_ENABLED)),
|
|
472
471
|
__param(4, (0, common_1.Optional)()),
|
|
473
472
|
__param(4, (0, common_1.Inject)(cache_constants_1.CACHE_COMPRESSION_THRESHOLD)),
|
|
473
|
+
__param(5, (0, common_1.Optional)()),
|
|
474
474
|
__metadata("design:paramtypes", [providers_1.ClsCacheProvider,
|
|
475
475
|
providers_1.LRUCacheProvider,
|
|
476
|
-
providers_1.RedisCacheProvider, Boolean, Number])
|
|
476
|
+
providers_1.RedisCacheProvider, Boolean, Number, cache_serialization_service_1.CacheSerializationService])
|
|
477
477
|
], CacheService);
|
|
@@ -71,13 +71,14 @@ function CachePut(options = {}) {
|
|
|
71
71
|
}
|
|
72
72
|
// Generate cache key
|
|
73
73
|
const key = utils_1.KeyGenerator.generate(options, args);
|
|
74
|
-
// Update cache with result
|
|
75
|
-
|
|
74
|
+
// Update cache with result - don't await, let it happen in background
|
|
75
|
+
cacheService.set(key, result, options).catch((error) => {
|
|
76
|
+
logger.warn(`Failed to update cache for ${target.constructor.name}.${methodName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
77
|
+
});
|
|
76
78
|
return result;
|
|
77
79
|
}
|
|
78
80
|
catch (error) {
|
|
79
|
-
|
|
80
|
-
// Re-throw the error (cache update failure shouldn't hide method errors)
|
|
81
|
+
// Method execution error - rethrow it
|
|
81
82
|
throw error;
|
|
82
83
|
}
|
|
83
84
|
});
|
|
@@ -65,6 +65,11 @@ class CallbackDependency {
|
|
|
65
65
|
return __awaiter(this, void 0, void 0, function* () {
|
|
66
66
|
try {
|
|
67
67
|
const currentData = yield this.getData();
|
|
68
|
+
// If oldData is null or undefined, consider it as changed
|
|
69
|
+
// (no previous valid data exists)
|
|
70
|
+
if (oldData === null || oldData === undefined) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
68
73
|
return !this.isEqual(oldData, currentData);
|
|
69
74
|
}
|
|
70
75
|
catch (_a) {
|
|
@@ -86,6 +91,10 @@ class CallbackDependency {
|
|
|
86
91
|
if (typeof a !== typeof b) {
|
|
87
92
|
return false;
|
|
88
93
|
}
|
|
94
|
+
// Handle Date objects
|
|
95
|
+
if (a instanceof Date && b instanceof Date) {
|
|
96
|
+
return a.getTime() === b.getTime();
|
|
97
|
+
}
|
|
89
98
|
if (typeof a !== 'object') {
|
|
90
99
|
return a === b;
|
|
91
100
|
}
|
|
@@ -28,6 +28,7 @@ export declare class TagDependency implements CacheDependency {
|
|
|
28
28
|
private readonly tags;
|
|
29
29
|
private static readonly PREFIX;
|
|
30
30
|
private static readonly REDIS_KEY_PREFIX;
|
|
31
|
+
private static readonly logger;
|
|
31
32
|
private static tagVersions;
|
|
32
33
|
private static redis;
|
|
33
34
|
constructor(tags: string[]);
|
|
@@ -71,15 +72,6 @@ export declare class TagDependency implements CacheDependency {
|
|
|
71
72
|
* @returns Map of tag names to versions
|
|
72
73
|
*/
|
|
73
74
|
static getAllTags(): Map<string, number>;
|
|
74
|
-
/**
|
|
75
|
-
* Get tag version (synchronous version for backward compatibility)
|
|
76
|
-
* Only reads from in-memory storage
|
|
77
|
-
*
|
|
78
|
-
* @deprecated Use getTagVersion(tag) instead for distributed support
|
|
79
|
-
* @param tag - Tag name
|
|
80
|
-
* @returns Current tag version from memory
|
|
81
|
-
*/
|
|
82
|
-
static getTagVersionSync(tag: string): number;
|
|
83
75
|
getKey(): string;
|
|
84
76
|
getData(): Promise<Record<string, number>>;
|
|
85
77
|
isChanged(oldData: Record<string, number>): Promise<boolean>;
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.TagDependency = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
13
14
|
/**
|
|
14
15
|
* Tag-based cache dependency
|
|
15
16
|
*
|
|
@@ -73,7 +74,7 @@ class TagDependency {
|
|
|
73
74
|
}
|
|
74
75
|
catch (error) {
|
|
75
76
|
// Log warning but don't throw - fall back to memory
|
|
76
|
-
|
|
77
|
+
TagDependency.logger.warn(`Failed to get tag version from Redis: ${error instanceof Error ? error.message : String(error)}`);
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
// Fall back to in-memory storage
|
|
@@ -99,7 +100,7 @@ class TagDependency {
|
|
|
99
100
|
yield TagDependency.redis.set(key, newVersion.toString());
|
|
100
101
|
}
|
|
101
102
|
catch (error) {
|
|
102
|
-
|
|
103
|
+
TagDependency.logger.error(`Failed to invalidate tag in Redis: ${error instanceof Error ? error.message : String(error)}`);
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
});
|
|
@@ -140,7 +141,7 @@ class TagDependency {
|
|
|
140
141
|
}
|
|
141
142
|
}
|
|
142
143
|
catch (error) {
|
|
143
|
-
|
|
144
|
+
TagDependency.logger.error(`Failed to reset tags in Redis: ${error instanceof Error ? error.message : String(error)}`);
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
});
|
|
@@ -154,17 +155,6 @@ class TagDependency {
|
|
|
154
155
|
static getAllTags() {
|
|
155
156
|
return new Map(TagDependency.tagVersions);
|
|
156
157
|
}
|
|
157
|
-
/**
|
|
158
|
-
* Get tag version (synchronous version for backward compatibility)
|
|
159
|
-
* Only reads from in-memory storage
|
|
160
|
-
*
|
|
161
|
-
* @deprecated Use getTagVersion(tag) instead for distributed support
|
|
162
|
-
* @param tag - Tag name
|
|
163
|
-
* @returns Current tag version from memory
|
|
164
|
-
*/
|
|
165
|
-
static getTagVersionSync(tag) {
|
|
166
|
-
return TagDependency.tagVersions.get(tag) || 0;
|
|
167
|
-
}
|
|
168
158
|
getKey() {
|
|
169
159
|
return `tag:${this.tags.sort().join(',')}`;
|
|
170
160
|
}
|
|
@@ -203,6 +193,7 @@ class TagDependency {
|
|
|
203
193
|
exports.TagDependency = TagDependency;
|
|
204
194
|
TagDependency.PREFIX = 'cache:tag:';
|
|
205
195
|
TagDependency.REDIS_KEY_PREFIX = 'cache:tag:versions';
|
|
196
|
+
TagDependency.logger = new common_1.Logger(TagDependency.name);
|
|
206
197
|
// In-memory fallback for when Redis is not available
|
|
207
198
|
TagDependency.tagVersions = new Map();
|
|
208
199
|
// Redis client for distributed tag version storage
|
|
@@ -17,6 +17,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
17
17
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
+
var LRUCacheProvider_1;
|
|
20
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
22
|
exports.LRUCacheProvider = void 0;
|
|
22
23
|
const common_1 = require("@nestjs/common");
|
|
@@ -51,9 +52,10 @@ const LRUCacheClass = require('lru-cache').LRUCache;
|
|
|
51
52
|
* });
|
|
52
53
|
* ```
|
|
53
54
|
*/
|
|
54
|
-
let LRUCacheProvider = class LRUCacheProvider extends base_cache_provider_1.BaseCacheProvider {
|
|
55
|
+
let LRUCacheProvider = LRUCacheProvider_1 = class LRUCacheProvider extends base_cache_provider_1.BaseCacheProvider {
|
|
55
56
|
constructor(options) {
|
|
56
57
|
super();
|
|
58
|
+
this.logger = new common_1.Logger(LRUCacheProvider_1.name);
|
|
57
59
|
const { maxSize = 500, ttl, namespace = 'cache:lru' } = options || {};
|
|
58
60
|
this.namespace = namespace;
|
|
59
61
|
this.defaultTtl = ttl;
|
|
@@ -75,7 +77,7 @@ let LRUCacheProvider = class LRUCacheProvider extends base_cache_provider_1.Base
|
|
|
75
77
|
return value !== undefined ? value : null;
|
|
76
78
|
}
|
|
77
79
|
catch (error) {
|
|
78
|
-
|
|
80
|
+
this.logger.warn(`Failed to get key ${key}: ${error instanceof Error ? error.message : String(error)}`);
|
|
79
81
|
return null;
|
|
80
82
|
}
|
|
81
83
|
});
|
|
@@ -161,7 +163,7 @@ let LRUCacheProvider = class LRUCacheProvider extends base_cache_provider_1.Base
|
|
|
161
163
|
});
|
|
162
164
|
}
|
|
163
165
|
catch (error) {
|
|
164
|
-
|
|
166
|
+
this.logger.warn(`Failed to mget: ${error instanceof Error ? error.message : String(error)}`);
|
|
165
167
|
return keys.map(() => null);
|
|
166
168
|
}
|
|
167
169
|
});
|
|
@@ -220,7 +222,7 @@ let LRUCacheProvider = class LRUCacheProvider extends base_cache_provider_1.Base
|
|
|
220
222
|
}
|
|
221
223
|
};
|
|
222
224
|
exports.LRUCacheProvider = LRUCacheProvider;
|
|
223
|
-
exports.LRUCacheProvider = LRUCacheProvider = __decorate([
|
|
225
|
+
exports.LRUCacheProvider = LRUCacheProvider = LRUCacheProvider_1 = __decorate([
|
|
224
226
|
(0, common_1.Injectable)(),
|
|
225
227
|
__metadata("design:paramtypes", [Object])
|
|
226
228
|
], LRUCacheProvider);
|
|
@@ -14,6 +14,7 @@ export declare const REDIS_CLIENT: unique symbol;
|
|
|
14
14
|
*/
|
|
15
15
|
export declare class RedisCacheProvider extends BaseCacheProvider {
|
|
16
16
|
private readonly redis?;
|
|
17
|
+
private readonly logger;
|
|
17
18
|
private readonly keyPrefix;
|
|
18
19
|
constructor(redis?: Redis);
|
|
19
20
|
getName(): string;
|
|
@@ -20,6 +20,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
20
20
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21
21
|
});
|
|
22
22
|
};
|
|
23
|
+
var RedisCacheProvider_1;
|
|
23
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
25
|
exports.RedisCacheProvider = exports.REDIS_CLIENT = void 0;
|
|
25
26
|
const common_1 = require("@nestjs/common");
|
|
@@ -36,13 +37,14 @@ exports.REDIS_CLIENT = Symbol('REDIS_CLIENT');
|
|
|
36
37
|
*
|
|
37
38
|
* Slowest but most persistent and widely shared cache layer.
|
|
38
39
|
*/
|
|
39
|
-
let RedisCacheProvider = class RedisCacheProvider extends base_cache_provider_1.BaseCacheProvider {
|
|
40
|
+
let RedisCacheProvider = RedisCacheProvider_1 = class RedisCacheProvider extends base_cache_provider_1.BaseCacheProvider {
|
|
40
41
|
constructor(redis) {
|
|
41
42
|
super();
|
|
42
43
|
this.redis = redis;
|
|
44
|
+
this.logger = new common_1.Logger(RedisCacheProvider_1.name);
|
|
43
45
|
this.keyPrefix = 'cache:';
|
|
44
46
|
if (!redis) {
|
|
45
|
-
|
|
47
|
+
this.logger.warn('Redis client not injected. Redis caching will be disabled.');
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
getName() {
|
|
@@ -62,7 +64,7 @@ let RedisCacheProvider = class RedisCacheProvider extends base_cache_provider_1.
|
|
|
62
64
|
return JSON.parse(value);
|
|
63
65
|
}
|
|
64
66
|
catch (error) {
|
|
65
|
-
|
|
67
|
+
this.logger.warn(`Failed to get key ${key}: ${error instanceof Error ? error.message : String(error)}`);
|
|
66
68
|
return null;
|
|
67
69
|
}
|
|
68
70
|
});
|
|
@@ -126,7 +128,7 @@ let RedisCacheProvider = class RedisCacheProvider extends base_cache_provider_1.
|
|
|
126
128
|
return deletedCount;
|
|
127
129
|
}
|
|
128
130
|
catch (error) {
|
|
129
|
-
|
|
131
|
+
this.logger.warn(`deletePattern failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
130
132
|
return 0;
|
|
131
133
|
}
|
|
132
134
|
});
|
|
@@ -184,7 +186,7 @@ let RedisCacheProvider = class RedisCacheProvider extends base_cache_provider_1.
|
|
|
184
186
|
});
|
|
185
187
|
}
|
|
186
188
|
catch (error) {
|
|
187
|
-
|
|
189
|
+
this.logger.warn(`mget failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
188
190
|
return keys.map(() => null);
|
|
189
191
|
}
|
|
190
192
|
});
|
|
@@ -236,7 +238,7 @@ let RedisCacheProvider = class RedisCacheProvider extends base_cache_provider_1.
|
|
|
236
238
|
}
|
|
237
239
|
};
|
|
238
240
|
exports.RedisCacheProvider = RedisCacheProvider;
|
|
239
|
-
exports.RedisCacheProvider = RedisCacheProvider = __decorate([
|
|
241
|
+
exports.RedisCacheProvider = RedisCacheProvider = RedisCacheProvider_1 = __decorate([
|
|
240
242
|
(0, common_1.Injectable)(),
|
|
241
243
|
__param(0, (0, common_1.Optional)()),
|
|
242
244
|
__param(0, (0, common_1.Inject)(exports.REDIS_CLIENT)),
|
|
@@ -10,7 +10,9 @@ exports.getHttpClientConfig = getHttpClientConfig;
|
|
|
10
10
|
function deepMerge(target, source) {
|
|
11
11
|
const result = Object.assign({}, target);
|
|
12
12
|
for (const key in source) {
|
|
13
|
-
if (source[key] instanceof Object &&
|
|
13
|
+
if (source[key] instanceof Object &&
|
|
14
|
+
key in target &&
|
|
15
|
+
!Array.isArray(source[key])) {
|
|
14
16
|
result[key] = deepMerge(target[key], source[key]);
|
|
15
17
|
}
|
|
16
18
|
else {
|
|
@@ -304,9 +304,7 @@ function environmentSpecificConfig() {
|
|
|
304
304
|
? (status) => status >= 200 && status < 500
|
|
305
305
|
: (status) => status >= 200 && status < 300,
|
|
306
306
|
// 开发环境禁用 keep-alive 以便调试
|
|
307
|
-
httpAgent: isDevelopment
|
|
308
|
-
? undefined
|
|
309
|
-
: new http_1.Agent({ keepAlive: true }),
|
|
307
|
+
httpAgent: isDevelopment ? undefined : new http_1.Agent({ keepAlive: true }),
|
|
310
308
|
},
|
|
311
309
|
};
|
|
312
310
|
return config;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HttpClientService 灵活返回示例
|
|
3
|
+
* 展示如何根据不同需求获取不同的响应数据
|
|
4
|
+
*/
|
|
5
|
+
import { HttpClientService } from '../services/http-client.service';
|
|
6
|
+
declare function getFullResponseExample(httpClient: HttpClientService): Promise<any>;
|
|
7
|
+
declare function getCustomResponseExample(httpClient: HttpClientService): Promise<any>;
|
|
8
|
+
declare function getPagedResponseExample(httpClient: HttpClientService): Promise<{
|
|
9
|
+
data: any;
|
|
10
|
+
currentPage: number;
|
|
11
|
+
pageSize: number;
|
|
12
|
+
totalPages: number;
|
|
13
|
+
totalItems: number;
|
|
14
|
+
hasNextPage: any;
|
|
15
|
+
hasPrevPage: any;
|
|
16
|
+
}>;
|
|
17
|
+
declare function getRedirectUrlExample(httpClient: HttpClientService): Promise<{
|
|
18
|
+
redirected: boolean;
|
|
19
|
+
url: any;
|
|
20
|
+
data?: undefined;
|
|
21
|
+
} | {
|
|
22
|
+
redirected: boolean;
|
|
23
|
+
data: any;
|
|
24
|
+
url?: undefined;
|
|
25
|
+
}>;
|
|
26
|
+
declare function getDefaultBehaviorExample(httpClient: HttpClientService): Promise<any>;
|
|
27
|
+
declare function conditionalReturnExample(httpClient: HttpClientService, needHeaders: boolean): Promise<any>;
|
|
28
|
+
export { getFullResponseExample, getCustomResponseExample, getPagedResponseExample, getRedirectUrlExample, getDefaultBehaviorExample, conditionalReturnExample, };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* HttpClientService 灵活返回示例
|
|
4
|
+
* 展示如何根据不同需求获取不同的响应数据
|
|
5
|
+
*/
|
|
6
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
7
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
8
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
9
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
10
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
11
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
12
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.getFullResponseExample = getFullResponseExample;
|
|
17
|
+
exports.getCustomResponseExample = getCustomResponseExample;
|
|
18
|
+
exports.getPagedResponseExample = getPagedResponseExample;
|
|
19
|
+
exports.getRedirectUrlExample = getRedirectUrlExample;
|
|
20
|
+
exports.getDefaultBehaviorExample = getDefaultBehaviorExample;
|
|
21
|
+
exports.conditionalReturnExample = conditionalReturnExample;
|
|
22
|
+
// 示例1: 获取完整响应对象(包含headers, status等)
|
|
23
|
+
function getFullResponseExample(httpClient) {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
// 返回完整的AxiosResponse对象
|
|
26
|
+
const fullResponse = yield httpClient.get('https://api.example.com/data', {}, // config
|
|
27
|
+
'my-client', // clientName
|
|
28
|
+
{ returnType: 'full' });
|
|
29
|
+
// 现在可以访问headers、status等信息
|
|
30
|
+
console.log('Status:', fullResponse.status);
|
|
31
|
+
console.log('Headers:', fullResponse.headers);
|
|
32
|
+
console.log('Data:', fullResponse.data);
|
|
33
|
+
// 例如检查特定header
|
|
34
|
+
const contentType = fullResponse.headers['content-type'];
|
|
35
|
+
const location = fullResponse.headers['location'];
|
|
36
|
+
return fullResponse.data; // 仍然可以获取data
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// 示例2: 自定义返回格式
|
|
40
|
+
function getCustomResponseExample(httpClient) {
|
|
41
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
// 自定义转换函数 - 只返回需要的字段
|
|
43
|
+
const customResponse = yield httpClient.get('https://api.example.com/users', {}, 'my-client', {
|
|
44
|
+
returnType: 'custom',
|
|
45
|
+
transform: (response) => {
|
|
46
|
+
var _a;
|
|
47
|
+
return ({
|
|
48
|
+
data: response.data,
|
|
49
|
+
totalCount: response.headers['x-total-count'],
|
|
50
|
+
currentPage: response.headers['x-current-page'],
|
|
51
|
+
hasNext: (_a = response.headers['link']) === null || _a === void 0 ? void 0 : _a.includes('rel="next"'),
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
console.log('Total Count:', customResponse.totalCount);
|
|
56
|
+
console.log('Has Next Page:', customResponse.hasNext);
|
|
57
|
+
return customResponse;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
// 示例3: 从headers中提取分页信息
|
|
61
|
+
function getPagedResponseExample(httpClient) {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
var _a, _b;
|
|
64
|
+
const response = yield httpClient.get('https://api.example.com/items?page=1&size=10', {}, 'my-client', { returnType: 'full' });
|
|
65
|
+
// 提取分页信息
|
|
66
|
+
const paginationInfo = {
|
|
67
|
+
data: response.data,
|
|
68
|
+
currentPage: parseInt(response.headers['x-page'] || '1'),
|
|
69
|
+
pageSize: parseInt(response.headers['x-per-page'] || '10'),
|
|
70
|
+
totalPages: parseInt(response.headers['x-total-pages'] || '1'),
|
|
71
|
+
totalItems: parseInt(response.headers['x-total-items'] || '0'),
|
|
72
|
+
hasNextPage: ((_a = response.headers['link']) === null || _a === void 0 ? void 0 : _a.includes('rel="next"')) || false,
|
|
73
|
+
hasPrevPage: ((_b = response.headers['link']) === null || _b === void 0 ? void 0 : _b.includes('rel="prev"')) || false,
|
|
74
|
+
};
|
|
75
|
+
return paginationInfo;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
// 示例4: 检查重定向URL
|
|
79
|
+
function getRedirectUrlExample(httpClient) {
|
|
80
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
81
|
+
const response = yield httpClient.get('https://api.example.com/redirect-me', { maxRedirects: 0 }, // 禁止自动重定向以便捕获Location header
|
|
82
|
+
'my-client', { returnType: 'full' });
|
|
83
|
+
// 对于3xx重定向状态,获取重定向URL
|
|
84
|
+
if (response.status >= 300 && response.status < 400) {
|
|
85
|
+
const redirectUrl = response.headers['location'];
|
|
86
|
+
console.log('Redirect URL:', redirectUrl);
|
|
87
|
+
return { redirected: true, url: redirectUrl };
|
|
88
|
+
}
|
|
89
|
+
return { redirected: false, data: response.data };
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// 示例5: 向后兼容 - 默认行为(只返回data)
|
|
93
|
+
function getDefaultBehaviorExample(httpClient) {
|
|
94
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
// 不传递returnOptions参数,保持原有行为
|
|
96
|
+
const data = yield httpClient.get('https://api.example.com/simple-data');
|
|
97
|
+
// 直接得到data,无需.response.data
|
|
98
|
+
console.log('Simple data:', data);
|
|
99
|
+
return data;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
// 示例6: 条件性返回不同格式
|
|
103
|
+
function conditionalReturnExample(httpClient, needHeaders) {
|
|
104
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
105
|
+
const returnOptions = needHeaders
|
|
106
|
+
? { returnType: 'full' }
|
|
107
|
+
: { returnType: 'data' }; // 默认
|
|
108
|
+
const result = yield httpClient.post('https://api.example.com/process', { action: 'calculate' }, {}, 'my-client', returnOptions);
|
|
109
|
+
if (needHeaders) {
|
|
110
|
+
// 处理完整响应
|
|
111
|
+
const fullResponse = result;
|
|
112
|
+
console.log('Processing time:', fullResponse.headers['x-processing-time']);
|
|
113
|
+
return fullResponse.data;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
// 直接使用data
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
@@ -27,10 +27,10 @@ export declare class DynamicCertificateManager {
|
|
|
27
27
|
cert?: string;
|
|
28
28
|
key?: string;
|
|
29
29
|
});
|
|
30
|
-
private loadCerts;
|
|
31
|
-
private buildConfig;
|
|
32
30
|
refreshCerts(): Promise<void>;
|
|
33
31
|
get(url: string): Promise<void>;
|
|
32
|
+
private loadCerts;
|
|
33
|
+
private buildConfig;
|
|
34
34
|
}
|
|
35
35
|
export declare const sslEnvVars: {
|
|
36
36
|
SSL_CA_PATH: string;
|
|
@@ -339,9 +339,26 @@ class DynamicCertificateManager {
|
|
|
339
339
|
this.cacheDuration = 5 * 60 * 1000; // 5分钟
|
|
340
340
|
this.httpClient = new index_1.HttpClientService(this.circuitBreakerService, this.loggingService, null, this.buildConfig());
|
|
341
341
|
}
|
|
342
|
+
// 重新创建客户端以使用新证书
|
|
343
|
+
refreshCerts() {
|
|
344
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
345
|
+
this.lastUpdate = 0;
|
|
346
|
+
const config = this.buildConfig();
|
|
347
|
+
// 在实际应用中,可能需要重新创建 HttpClientService 实例
|
|
348
|
+
// 或者提供更新配置的方法
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
get(url) {
|
|
352
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
353
|
+
// 每次请求前检查是否需要更新证书
|
|
354
|
+
this.loadCerts();
|
|
355
|
+
// return this.httpClient.get(url);
|
|
356
|
+
});
|
|
357
|
+
}
|
|
342
358
|
loadCerts() {
|
|
343
359
|
const now = Date.now();
|
|
344
|
-
if (now - this.lastUpdate < this.cacheDuration &&
|
|
360
|
+
if (now - this.lastUpdate < this.cacheDuration &&
|
|
361
|
+
Object.keys(this.certCache).length > 0) {
|
|
345
362
|
return this.certCache;
|
|
346
363
|
}
|
|
347
364
|
// 重新加载证书
|
|
@@ -367,22 +384,6 @@ class DynamicCertificateManager {
|
|
|
367
384
|
},
|
|
368
385
|
};
|
|
369
386
|
}
|
|
370
|
-
// 重新创建客户端以使用新证书
|
|
371
|
-
refreshCerts() {
|
|
372
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
373
|
-
this.lastUpdate = 0;
|
|
374
|
-
const config = this.buildConfig();
|
|
375
|
-
// 在实际应用中,可能需要重新创建 HttpClientService 实例
|
|
376
|
-
// 或者提供更新配置的方法
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
get(url) {
|
|
380
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
381
|
-
// 每次请求前检查是否需要更新证书
|
|
382
|
-
this.loadCerts();
|
|
383
|
-
// return this.httpClient.get(url);
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
387
|
}
|
|
387
388
|
exports.DynamicCertificateManager = DynamicCertificateManager;
|
|
388
389
|
// ============================================================================
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ApiClientConfig, ApiClientInstanceConfig, ApiClientRegistryConfig, AuthType, ResponseTransformerConfig } from '../interfaces/api-client-config.interface';
|
|
2
2
|
import { HttpCircuitBreakerService } from './circuit-breaker.service';
|
|
3
3
|
import { HttpLoggingService } from './logging.service';
|
|
4
|
-
export { ApiClientInstanceConfig, AuthType, ResponseTransformerConfig
|
|
4
|
+
export { ApiClientInstanceConfig, AuthType, ResponseTransformerConfig };
|
|
5
5
|
/**
|
|
6
6
|
* API客户端注册服务
|
|
7
7
|
* 负责管理多个 HttpClientService 实例
|
|
@@ -19,11 +19,6 @@ export declare class ApiClientRegistryService {
|
|
|
19
19
|
* 使用 HttpClientService.createApiClient 静态方法创建
|
|
20
20
|
*/
|
|
21
21
|
createClient<T = any>(config: ApiClientInstanceConfig): T;
|
|
22
|
-
/**
|
|
23
|
-
* 深度合并配置(已废弃,不再需要)
|
|
24
|
-
* @deprecated 配置结构简化后不再需要此方法
|
|
25
|
-
*/
|
|
26
|
-
private deepMergeConfigs;
|
|
27
22
|
/**
|
|
28
23
|
* 获取已注册的客户端
|
|
29
24
|
*/
|
|
@@ -78,6 +73,11 @@ export declare class ApiClientRegistryService {
|
|
|
78
73
|
error?: string;
|
|
79
74
|
}>;
|
|
80
75
|
}>;
|
|
76
|
+
/**
|
|
77
|
+
* 深度合并配置(已废弃,不再需要)
|
|
78
|
+
* @deprecated 配置结构简化后不再需要此方法
|
|
79
|
+
*/
|
|
80
|
+
private deepMergeConfigs;
|
|
81
81
|
/**
|
|
82
82
|
* 合并环境特定配置
|
|
83
83
|
*/
|
|
@@ -74,7 +74,7 @@ let ApiClientRegistryService = ApiClientRegistryService_1 = class ApiClientRegis
|
|
|
74
74
|
// 1. 从全局默认配置开始
|
|
75
75
|
// 2. 合并 ApiClient 的 httpConfig
|
|
76
76
|
// 3. 应用 ApiClient 特有的 retry 配置(兼容旧代码)
|
|
77
|
-
|
|
77
|
+
const mergedHttpConfig = Object.assign(Object.assign({}, this.globalDefaults.globalDefaults), finalConfig.httpConfig);
|
|
78
78
|
// 兼容:如果 ApiClientConfig 顶层有 retry 配置,合并到 httpConfig.retry
|
|
79
79
|
if (finalConfig.retry) {
|
|
80
80
|
mergedHttpConfig.retry = Object.assign(Object.assign({}, mergedHttpConfig.retry), finalConfig.retry);
|
|
@@ -95,13 +95,6 @@ let ApiClientRegistryService = ApiClientRegistryService_1 = class ApiClientRegis
|
|
|
95
95
|
this.logger.log(`Created API client: ${clientName}`);
|
|
96
96
|
return httpClient;
|
|
97
97
|
}
|
|
98
|
-
/**
|
|
99
|
-
* 深度合并配置(已废弃,不再需要)
|
|
100
|
-
* @deprecated 配置结构简化后不再需要此方法
|
|
101
|
-
*/
|
|
102
|
-
deepMergeConfigs(defaults, userConfig) {
|
|
103
|
-
return Object.assign(Object.assign({}, defaults), userConfig);
|
|
104
|
-
}
|
|
105
98
|
/**
|
|
106
99
|
* 获取已注册的客户端
|
|
107
100
|
*/
|
|
@@ -226,6 +219,13 @@ let ApiClientRegistryService = ApiClientRegistryService_1 = class ApiClientRegis
|
|
|
226
219
|
};
|
|
227
220
|
});
|
|
228
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* 深度合并配置(已废弃,不再需要)
|
|
224
|
+
* @deprecated 配置结构简化后不再需要此方法
|
|
225
|
+
*/
|
|
226
|
+
deepMergeConfigs(defaults, userConfig) {
|
|
227
|
+
return Object.assign(Object.assign({}, defaults), userConfig);
|
|
228
|
+
}
|
|
229
229
|
/**
|
|
230
230
|
* 合并环境特定配置
|
|
231
231
|
*/
|