@reskin/core 0.0.21 → 0.1.0
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/bundles/reskin-core-directives.umd.js +303 -163
- package/bundles/reskin-core-directives.umd.js.map +1 -1
- package/bundles/reskin-core-guards.umd.js +119 -32
- package/bundles/reskin-core-guards.umd.js.map +1 -1
- package/bundles/reskin-core-interceptors.umd.js +310 -92
- package/bundles/reskin-core-interceptors.umd.js.map +1 -1
- package/bundles/reskin-core-utils.umd.js +220 -77
- package/bundles/reskin-core-utils.umd.js.map +1 -1
- package/directives/auth.directive.d.ts +56 -9
- package/directives/load.styles.directive.d.ts +45 -5
- package/directives/string.template.outlet.directive.d.ts +68 -11
- package/esm2015/directives/auth.directive.js +71 -30
- package/esm2015/directives/load.styles.directive.js +84 -15
- package/esm2015/directives/string.template.outlet.directive.js +118 -60
- package/esm2015/guards/auth.guard.js +117 -30
- package/esm2015/interceptors/blob.interceptor.js +67 -28
- package/esm2015/interceptors/cache.interceptor.js +46 -14
- package/esm2015/interceptors/error.interceptor.js +104 -12
- package/esm2015/interceptors/public-api.js +2 -1
- package/esm2015/interceptors/token.interceptor.js +86 -42
- package/esm2015/interceptors/types.js +5 -0
- package/esm2015/utils/array.js +42 -22
- package/esm2015/utils/dom.js +29 -11
- package/esm2015/utils/form.js +44 -13
- package/esm2015/utils/store.js +101 -26
- package/fesm2015/reskin-core-directives.js +269 -103
- package/fesm2015/reskin-core-directives.js.map +1 -1
- package/fesm2015/reskin-core-guards.js +116 -29
- package/fesm2015/reskin-core-guards.js.map +1 -1
- package/fesm2015/reskin-core-interceptors.js +302 -91
- package/fesm2015/reskin-core-interceptors.js.map +1 -1
- package/fesm2015/reskin-core-utils.js +212 -68
- package/fesm2015/reskin-core-utils.js.map +1 -1
- package/guards/auth.guard.d.ts +85 -5
- package/interceptors/blob.interceptor.d.ts +30 -3
- package/interceptors/cache.interceptor.d.ts +28 -4
- package/interceptors/error.interceptor.d.ts +43 -2
- package/interceptors/public-api.d.ts +1 -0
- package/interceptors/token.interceptor.d.ts +41 -12
- package/interceptors/types.d.ts +68 -0
- package/package.json +1 -1
- package/utils/array.d.ts +8 -1
- package/utils/dom.d.ts +32 -5
- package/utils/form.d.ts +37 -2
- package/utils/store.d.ts +56 -15
|
@@ -2,35 +2,63 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { Injectable } from '@angular/core';
|
|
3
3
|
import { HTTP_INTERCEPTORS, HttpHeaders, HttpEventType, HttpResponse } from '@angular/common/http';
|
|
4
4
|
import * as i1 from '@reskin/core/services';
|
|
5
|
-
import {
|
|
5
|
+
import { throwError, Observable } from 'rxjs';
|
|
6
6
|
import { catchError, shareReplay, switchMap } from 'rxjs/operators';
|
|
7
7
|
import * as i1$1 from '@angular/router';
|
|
8
|
+
import { Router } from '@angular/router';
|
|
8
9
|
|
|
10
|
+
/**
|
|
11
|
+
* HTTP 拦截器相关类型定义
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Token 拦截器常量
|
|
16
|
+
*/
|
|
17
|
+
const DEFAULT_TOKEN_HEADER_NAME = 'Authorization';
|
|
18
|
+
const TOKEN_CONTROL_HEADER = 'Token-Control';
|
|
19
|
+
const CUSTOM_TOKEN_HEADER = 'Custom-Token';
|
|
20
|
+
const CUSTOM_TOKEN_HEADER_NAME = 'Custom-Token-Header';
|
|
21
|
+
const AUTH_ID_HEADER = 'X-Auth-Id';
|
|
22
|
+
/**
|
|
23
|
+
* Token 拦截器
|
|
24
|
+
* 自动为 HTTP 请求添加认证 Token
|
|
25
|
+
*/
|
|
9
26
|
class TokenInterceptor {
|
|
10
|
-
constructor(
|
|
11
|
-
this.
|
|
27
|
+
constructor(authService) {
|
|
28
|
+
this.authService = authService;
|
|
12
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* 拦截 HTTP 请求,添加 Token 认证信息
|
|
32
|
+
* @param request HTTP 请求对象
|
|
33
|
+
* @param next 下一个拦截器处理器
|
|
34
|
+
* @returns Observable<HttpEvent<unknown>>
|
|
35
|
+
*/
|
|
13
36
|
intercept(request, next) {
|
|
14
|
-
const
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
const tokenControl = request.headers.get(TOKEN_CONTROL_HEADER);
|
|
38
|
+
// 如果明确指定不需要 Token,直接放行
|
|
39
|
+
if (tokenControl === 'no-token') {
|
|
40
|
+
return next.handle(request);
|
|
41
|
+
}
|
|
42
|
+
const customToken = request.headers.get(CUSTOM_TOKEN_HEADER);
|
|
43
|
+
const customTokenHeaderName = request.headers.get(CUSTOM_TOKEN_HEADER_NAME) || DEFAULT_TOKEN_HEADER_NAME;
|
|
44
|
+
const headers = {};
|
|
45
|
+
if (customToken) {
|
|
46
|
+
// 使用自定义 Token
|
|
47
|
+
headers[customTokenHeaderName] = customToken;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// 使用默认认证信息
|
|
51
|
+
const auth = this.authService.token;
|
|
52
|
+
if (auth === null || auth === void 0 ? void 0 : auth.token) {
|
|
53
|
+
headers[DEFAULT_TOKEN_HEADER_NAME] = auth.token;
|
|
54
|
+
if (auth.id) {
|
|
55
|
+
headers[AUTH_ID_HEADER] = auth.id;
|
|
29
56
|
}
|
|
30
57
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
58
|
+
}
|
|
59
|
+
// 如果有需要添加的 Header,克隆请求并添加
|
|
60
|
+
if (Object.keys(headers).length > 0) {
|
|
61
|
+
request = request.clone({ setHeaders: headers });
|
|
34
62
|
}
|
|
35
63
|
return next.handle(request);
|
|
36
64
|
}
|
|
@@ -41,55 +69,141 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImpo
|
|
|
41
69
|
type: Injectable
|
|
42
70
|
}], ctorParameters: function () { return [{ type: i1.RkAuthService }]; } });
|
|
43
71
|
/**
|
|
44
|
-
*
|
|
72
|
+
* 提供 Token 拦截器
|
|
73
|
+
* @returns Provider 配置对象
|
|
45
74
|
*/
|
|
46
75
|
function providerAuthToken() {
|
|
47
76
|
return { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true };
|
|
48
77
|
}
|
|
49
78
|
/**
|
|
50
|
-
*
|
|
51
|
-
* @param urls
|
|
52
|
-
* @param params
|
|
53
|
-
* @
|
|
79
|
+
* 创建不带 Token 的请求配置
|
|
80
|
+
* @param urls 模板字符串数组
|
|
81
|
+
* @param params 模板参数
|
|
82
|
+
* @returns [url, options] 元组
|
|
83
|
+
* @example
|
|
84
|
+
* this.http.get(...NoAuthTokenTemplate`/api/public/data`).subscribe();
|
|
54
85
|
*/
|
|
55
86
|
function NoAuthTokenTemplate(urls, ...params) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
url = String.raw(urls, ...params);
|
|
59
|
-
}
|
|
60
|
-
return [url, { headers: new HttpHeaders({ 'Token-Control': 'no-token' }) }];
|
|
87
|
+
const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];
|
|
88
|
+
return [url, { headers: new HttpHeaders({ [TOKEN_CONTROL_HEADER]: 'no-token' }) }];
|
|
61
89
|
}
|
|
62
90
|
/**
|
|
63
|
-
*
|
|
64
|
-
* @param
|
|
65
|
-
* @param
|
|
66
|
-
* @
|
|
91
|
+
* 创建使用自定义 Token 的请求配置
|
|
92
|
+
* @param token 自定义 Token 值
|
|
93
|
+
* @param urls 模板字符串数组
|
|
94
|
+
* @param params 模板参数
|
|
95
|
+
* @returns [url, options] 元组
|
|
96
|
+
* @example
|
|
97
|
+
* this.http.get(...CustomTokenTemplate('my-token', `/api/data`)).subscribe();
|
|
67
98
|
*/
|
|
68
|
-
function CustomTokenTemplate(urls, ...params) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
99
|
+
function CustomTokenTemplate(token, urls, ...params) {
|
|
100
|
+
const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];
|
|
101
|
+
return [url, { headers: new HttpHeaders({ [CUSTOM_TOKEN_HEADER]: token }) }];
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 创建使用自定义 Token 和自定义 Header 名称的请求配置
|
|
105
|
+
* @param token 自定义 Token 值
|
|
106
|
+
* @param headerName 自定义 Header 名称
|
|
107
|
+
* @param urls 模板字符串数组
|
|
108
|
+
* @param params 模板参数
|
|
109
|
+
* @returns [url, options] 元组
|
|
110
|
+
* @example
|
|
111
|
+
* this.http.get(...CustomTokenWithHeaderTemplate('my-token', 'X-API-Key', `/api/data`)).subscribe();
|
|
112
|
+
*/
|
|
113
|
+
function CustomTokenWithHeaderTemplate(token, headerName, urls, ...params) {
|
|
114
|
+
const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];
|
|
115
|
+
return [
|
|
116
|
+
url,
|
|
117
|
+
{
|
|
118
|
+
headers: new HttpHeaders({
|
|
119
|
+
[CUSTOM_TOKEN_HEADER]: token,
|
|
120
|
+
[CUSTOM_TOKEN_HEADER_NAME]: headerName,
|
|
121
|
+
}),
|
|
122
|
+
},
|
|
123
|
+
];
|
|
75
124
|
}
|
|
76
125
|
|
|
126
|
+
/**
|
|
127
|
+
* 默认配置
|
|
128
|
+
*/
|
|
129
|
+
const DEFAULT_CONFIG = {
|
|
130
|
+
unauthorizedPath: '/errors/401',
|
|
131
|
+
enableLogging: false,
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* HTTP 错误拦截器
|
|
135
|
+
* 统一处理 HTTP 请求错误,包括 401 未授权错误的自动跳转
|
|
136
|
+
*/
|
|
77
137
|
class ErrorInterceptor {
|
|
78
138
|
constructor(router) {
|
|
79
139
|
this.router = router;
|
|
140
|
+
this.config = DEFAULT_CONFIG;
|
|
80
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* 设置拦截器配置
|
|
144
|
+
* @param config 配置对象
|
|
145
|
+
*/
|
|
146
|
+
setConfig(config) {
|
|
147
|
+
this.config = Object.assign(Object.assign({}, DEFAULT_CONFIG), config);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* 拦截 HTTP 请求,处理错误响应
|
|
151
|
+
* @param request HTTP 请求对象
|
|
152
|
+
* @param next 下一个拦截器处理器
|
|
153
|
+
* @returns Observable<HttpEvent<unknown>>
|
|
154
|
+
*/
|
|
81
155
|
intercept(request, next) {
|
|
82
|
-
return next.handle(request).pipe(catchError((
|
|
83
|
-
|
|
84
|
-
if (
|
|
85
|
-
this.
|
|
156
|
+
return next.handle(request).pipe(catchError((error) => {
|
|
157
|
+
// 处理 401 未授权错误
|
|
158
|
+
if (error.status === 401) {
|
|
159
|
+
this.handleUnauthorizedError();
|
|
160
|
+
return throwError(error);
|
|
86
161
|
}
|
|
87
|
-
|
|
88
|
-
|
|
162
|
+
// 记录错误日志
|
|
163
|
+
if (this.config.enableLogging) {
|
|
164
|
+
console.error('[HTTP Error]', {
|
|
165
|
+
url: request.url,
|
|
166
|
+
method: request.method,
|
|
167
|
+
status: error.status,
|
|
168
|
+
message: error.message,
|
|
169
|
+
error: error.error,
|
|
170
|
+
});
|
|
89
171
|
}
|
|
90
|
-
|
|
172
|
+
// 提取错误信息
|
|
173
|
+
const errorMessage = this.extractErrorMessage(error);
|
|
174
|
+
return throwError(new Error(errorMessage));
|
|
91
175
|
}));
|
|
92
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* 处理 401 未授权错误
|
|
179
|
+
*/
|
|
180
|
+
handleUnauthorizedError() {
|
|
181
|
+
const path = this.config.unauthorizedPath || DEFAULT_CONFIG.unauthorizedPath;
|
|
182
|
+
this.router.navigate([path]).catch((err) => {
|
|
183
|
+
console.error('导航到错误页面失败:', err);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* 提取错误信息
|
|
188
|
+
* @param error HTTP 错误响应
|
|
189
|
+
* @returns 错误信息字符串
|
|
190
|
+
*/
|
|
191
|
+
extractErrorMessage(error) {
|
|
192
|
+
if (error.error) {
|
|
193
|
+
// 尝试从 error.error 中提取信息
|
|
194
|
+
if (typeof error.error === 'string') {
|
|
195
|
+
return error.error;
|
|
196
|
+
}
|
|
197
|
+
if (error.error.msg) {
|
|
198
|
+
return error.error.msg;
|
|
199
|
+
}
|
|
200
|
+
if (error.error.message) {
|
|
201
|
+
return error.error.message;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// 使用默认错误信息
|
|
205
|
+
return error.message || `HTTP Error ${error.status}`;
|
|
206
|
+
}
|
|
93
207
|
}
|
|
94
208
|
ErrorInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: ErrorInterceptor, deps: [{ token: i1$1.Router }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
95
209
|
ErrorInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: ErrorInterceptor });
|
|
@@ -97,28 +211,71 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImpo
|
|
|
97
211
|
type: Injectable
|
|
98
212
|
}], ctorParameters: function () { return [{ type: i1$1.Router }]; } });
|
|
99
213
|
/**
|
|
100
|
-
*
|
|
214
|
+
* 提供 HTTP 错误拦截器
|
|
215
|
+
* @param config 可选的配置对象
|
|
216
|
+
* @returns Provider 配置对象
|
|
217
|
+
* @example
|
|
218
|
+
* providers: [
|
|
219
|
+
* providerHttpError({ unauthorizedPath: '/login', enableLogging: true })
|
|
220
|
+
* ]
|
|
101
221
|
*/
|
|
102
|
-
function providerHttpError() {
|
|
103
|
-
|
|
222
|
+
function providerHttpError(config) {
|
|
223
|
+
if (config) {
|
|
224
|
+
// 如果有配置,使用 useFactory
|
|
225
|
+
return {
|
|
226
|
+
provide: HTTP_INTERCEPTORS,
|
|
227
|
+
useFactory: (router) => {
|
|
228
|
+
const interceptor = new ErrorInterceptor(router);
|
|
229
|
+
interceptor.setConfig(config);
|
|
230
|
+
return interceptor;
|
|
231
|
+
},
|
|
232
|
+
deps: [Router],
|
|
233
|
+
multi: true,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
// 没有配置,直接使用 useClass
|
|
238
|
+
return {
|
|
239
|
+
provide: HTTP_INTERCEPTORS,
|
|
240
|
+
useClass: ErrorInterceptor,
|
|
241
|
+
multi: true,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
104
244
|
}
|
|
105
245
|
|
|
246
|
+
/**
|
|
247
|
+
* 缓存策略标识
|
|
248
|
+
*/
|
|
249
|
+
const CACHE_HEADER = 'Cache-Map';
|
|
250
|
+
const CACHE_STRATEGY = 'Storage';
|
|
251
|
+
/**
|
|
252
|
+
* HTTP 缓存拦截器
|
|
253
|
+
* 为 GET 请求提供缓存功能,减少重复请求
|
|
254
|
+
*/
|
|
106
255
|
class CacheInterceptor {
|
|
107
|
-
constructor(
|
|
108
|
-
this.
|
|
256
|
+
constructor(cacheHttpService) {
|
|
257
|
+
this.cacheHttpService = cacheHttpService;
|
|
109
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* 拦截 HTTP 请求,实现缓存逻辑
|
|
261
|
+
* @param request HTTP 请求对象
|
|
262
|
+
* @param next 下一个拦截器处理器
|
|
263
|
+
* @returns Observable<HttpEvent<unknown>>
|
|
264
|
+
*/
|
|
110
265
|
intercept(request, next) {
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
let
|
|
116
|
-
if (!
|
|
117
|
-
|
|
118
|
-
|
|
266
|
+
// 只缓存 GET 请求且明确标记了缓存策略的请求
|
|
267
|
+
const cacheStrategy = request.headers.get(CACHE_HEADER);
|
|
268
|
+
if (request.method === 'GET' && cacheStrategy === CACHE_STRATEGY) {
|
|
269
|
+
// 尝试从缓存中获取响应
|
|
270
|
+
let cachedResponse = this.cacheHttpService.get(request.url);
|
|
271
|
+
if (!cachedResponse) {
|
|
272
|
+
// 缓存未命中,发起请求并缓存结果
|
|
273
|
+
cachedResponse = next.handle(request).pipe(shareReplay(1));
|
|
274
|
+
this.cacheHttpService.set(request.url, cachedResponse);
|
|
119
275
|
}
|
|
120
|
-
return
|
|
276
|
+
return cachedResponse;
|
|
121
277
|
}
|
|
278
|
+
// 非缓存请求,直接放行
|
|
122
279
|
return next.handle(request);
|
|
123
280
|
}
|
|
124
281
|
}
|
|
@@ -128,58 +285,110 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImpo
|
|
|
128
285
|
type: Injectable
|
|
129
286
|
}], ctorParameters: function () { return [{ type: i1.RkCacheHttpService }]; } });
|
|
130
287
|
/**
|
|
131
|
-
*
|
|
288
|
+
* 提供 HTTP 缓存拦截器
|
|
289
|
+
* @returns Provider 配置对象
|
|
290
|
+
* @example
|
|
291
|
+
* providers: [providerHttpCache()]
|
|
132
292
|
*/
|
|
133
293
|
function providerHttpCache() {
|
|
134
294
|
return { provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true };
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* 创建带缓存标记的 GET 请求配置
|
|
298
|
+
* @param urls 模板字符串数组
|
|
299
|
+
* @param params 模板参数
|
|
300
|
+
* @returns [url, options] 元组
|
|
301
|
+
* @example
|
|
302
|
+
* this.http.get(...CacheHttpTemplate`/api/data`).subscribe();
|
|
303
|
+
*/
|
|
304
|
+
function CacheHttpTemplate(urls, ...params) {
|
|
305
|
+
const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];
|
|
306
|
+
return [url, { headers: new HttpHeaders({ [CACHE_HEADER]: CACHE_STRATEGY }) }];
|
|
135
307
|
}
|
|
136
308
|
|
|
309
|
+
/**
|
|
310
|
+
* Blob 响应拦截器
|
|
311
|
+
* 处理文件下载请求中的 JSON 错误响应
|
|
312
|
+
*/
|
|
137
313
|
class BlobInterceptor {
|
|
314
|
+
/**
|
|
315
|
+
* 拦截 HTTP 请求,处理 Blob 类型响应
|
|
316
|
+
* @param request HTTP 请求对象
|
|
317
|
+
* @param next 下一个拦截器处理器
|
|
318
|
+
* @returns Observable<HttpEvent<T>>
|
|
319
|
+
*/
|
|
138
320
|
intercept(request, next) {
|
|
321
|
+
// 只处理 responseType 为 blob 的请求
|
|
139
322
|
if (request.responseType !== 'blob') {
|
|
140
323
|
return next.handle(request);
|
|
141
324
|
}
|
|
142
|
-
return next.handle(request).pipe(switchMap((
|
|
325
|
+
return next.handle(request).pipe(switchMap((event) => this.handleBlobResponse(event)), catchError((error) => this.handleBlobError(error)));
|
|
143
326
|
}
|
|
144
|
-
|
|
145
|
-
|
|
327
|
+
/**
|
|
328
|
+
* 处理 Blob 响应事件
|
|
329
|
+
* @param event HTTP 事件
|
|
330
|
+
* @returns Observable<HttpEvent<any>>
|
|
331
|
+
*/
|
|
332
|
+
handleBlobResponse(event) {
|
|
333
|
+
var _a;
|
|
334
|
+
// 只处理完整的响应事件
|
|
335
|
+
if (event.type !== HttpEventType.Response) {
|
|
146
336
|
return new Observable((subscriber) => {
|
|
147
|
-
subscriber.next(
|
|
337
|
+
subscriber.next(event);
|
|
148
338
|
subscriber.complete();
|
|
149
339
|
});
|
|
150
340
|
}
|
|
151
|
-
|
|
152
|
-
|
|
341
|
+
// 检查响应体是否为 JSON 类型(通常表示错误)
|
|
342
|
+
if (event instanceof HttpResponse && ((_a = event.body) === null || _a === void 0 ? void 0 : _a.type) === 'application/json') {
|
|
343
|
+
return this.convertBlobToJson(event.body);
|
|
153
344
|
}
|
|
154
345
|
return new Observable((subscriber) => {
|
|
155
|
-
subscriber.next(
|
|
346
|
+
subscriber.next(event);
|
|
156
347
|
subscriber.complete();
|
|
157
348
|
});
|
|
158
349
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
350
|
+
/**
|
|
351
|
+
* 处理 Blob 错误响应
|
|
352
|
+
* @param error HTTP 错误响应
|
|
353
|
+
* @returns Observable<HttpEvent<any>>
|
|
354
|
+
*/
|
|
355
|
+
handleBlobError(error) {
|
|
356
|
+
var _a;
|
|
357
|
+
// 如果错误响应体是 JSON 类型的 Blob,转换为 JSON 对象
|
|
358
|
+
if (((_a = error.error) === null || _a === void 0 ? void 0 : _a.type) === 'application/json') {
|
|
359
|
+
return this.convertBlobToJson(error.error);
|
|
162
360
|
}
|
|
163
361
|
return new Observable((subscriber) => {
|
|
164
|
-
subscriber.error(
|
|
362
|
+
subscriber.error(error);
|
|
165
363
|
subscriber.complete();
|
|
166
364
|
});
|
|
167
365
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
366
|
+
/**
|
|
367
|
+
* 将 Blob 转换为 JSON 对象并抛出错误
|
|
368
|
+
* @param blob Blob 对象
|
|
369
|
+
* @returns Observable<HttpEvent<T>>
|
|
370
|
+
*/
|
|
371
|
+
convertBlobToJson(blob) {
|
|
372
|
+
return new Observable((subscriber) => {
|
|
373
|
+
const reader = new FileReader();
|
|
374
|
+
reader.addEventListener('loadend', () => {
|
|
375
|
+
try {
|
|
376
|
+
const json = JSON.parse(reader.result);
|
|
377
|
+
subscriber.error(json);
|
|
378
|
+
}
|
|
379
|
+
catch (parseError) {
|
|
380
|
+
subscriber.error(parseError);
|
|
381
|
+
}
|
|
382
|
+
finally {
|
|
383
|
+
subscriber.complete();
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
reader.addEventListener('error', () => {
|
|
387
|
+
subscriber.error(new Error('读取 Blob 数据失败'));
|
|
179
388
|
subscriber.complete();
|
|
180
|
-
}
|
|
389
|
+
});
|
|
390
|
+
reader.readAsText(blob, 'utf-8');
|
|
181
391
|
});
|
|
182
|
-
reader.readAsText(blob, 'utf-8');
|
|
183
392
|
}
|
|
184
393
|
}
|
|
185
394
|
BlobInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: BlobInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
@@ -188,8 +397,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImpo
|
|
|
188
397
|
type: Injectable
|
|
189
398
|
}] });
|
|
190
399
|
/**
|
|
191
|
-
*
|
|
192
|
-
*
|
|
400
|
+
* 提供 Blob 响应拦截器
|
|
401
|
+
* @returns Provider 配置对象
|
|
402
|
+
* @example
|
|
403
|
+
* providers: [providerDownBlob()]
|
|
193
404
|
*/
|
|
194
405
|
function providerDownBlob() {
|
|
195
406
|
return { provide: HTTP_INTERCEPTORS, useClass: BlobInterceptor, multi: true };
|
|
@@ -199,5 +410,5 @@ function providerDownBlob() {
|
|
|
199
410
|
* Generated bundle index. Do not edit.
|
|
200
411
|
*/
|
|
201
412
|
|
|
202
|
-
export { BlobInterceptor, CacheInterceptor, CustomTokenTemplate, ErrorInterceptor, NoAuthTokenTemplate, TokenInterceptor, providerAuthToken, providerDownBlob, providerHttpCache, providerHttpError };
|
|
413
|
+
export { BlobInterceptor, CacheHttpTemplate, CacheInterceptor, CustomTokenTemplate, CustomTokenWithHeaderTemplate, ErrorInterceptor, NoAuthTokenTemplate, TokenInterceptor, providerAuthToken, providerDownBlob, providerHttpCache, providerHttpError };
|
|
203
414
|
//# sourceMappingURL=reskin-core-interceptors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reskin-core-interceptors.js","sources":["../../../library/core/interceptors/token.interceptor.ts","../../../library/core/interceptors/error.interceptor.ts","../../../library/core/interceptors/cache.interceptor.ts","../../../library/core/interceptors/blob.interceptor.ts","../../../library/core/interceptors/reskin-core-interceptors.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\r\nimport { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS, HttpHeaders } from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\nimport { RkAuthService } from '@reskin/core/services';\r\nimport { IAuth } from '@reskin/core/entity/user';\r\n\r\n@Injectable()\r\nexport class TokenInterceptor implements HttpInterceptor {\r\n constructor(private service: RkAuthService) {}\r\n\r\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\r\n const tc = request.headers.get('Token-Control');\r\n // 检查是否提供了自定义token\r\n const customToken = request.headers.get('Custom-Token');\r\n\r\n if (tc !== 'no-token') {\r\n let headers: { [name: string]: string | string[] } = {};\r\n\r\n if (customToken) {\r\n // 使用自定义token\r\n headers['Authorization'] = customToken;\r\n } else {\r\n // 使用默认认证信息\r\n const auth: IAuth = this.service.token;\r\n if (auth.token) {\r\n headers['Authorization'] = auth.token;\r\n headers['X-Auth-Id'] = auth.id;\r\n }\r\n }\r\n\r\n if (Object.keys(headers).length > 0) {\r\n request = request.clone({ setHeaders: headers });\r\n }\r\n }\r\n return next.handle(request);\r\n }\r\n}\r\n\r\n/**\r\n * 请求头增加token验证拦截器\r\n */\r\nexport function providerAuthToken() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true };\r\n}\r\n\r\n/**\r\n * 不带token验证信息请求\r\n * @param urls 地址\r\n * @param params 参数\r\n * @constructor\r\n */\r\nexport function NoAuthTokenTemplate(urls: TemplateStringsArray, ...params: any[]): [string, { headers: HttpHeaders }] {\r\n let [url] = urls;\r\n if (params.length > 0) {\r\n url = String.raw(urls, ...params);\r\n }\r\n return [url, { headers: new HttpHeaders({ 'Token-Control': 'no-token' }) }];\r\n}\r\n\r\n/**\r\n * 使用自定义token的请求(模板字符串版本)\r\n * @param urls 地址\r\n * @param params 参数,第一个参数必须是token值\r\n * @constructor\r\n */\r\nexport function CustomTokenTemplate(urls: TemplateStringsArray, ...params: any[]): [string, { headers: HttpHeaders }] {\r\n if (params.length === 0) {\r\n throw new Error('CustomTokenTemplate 至少需要一个参数作为token值');\r\n }\r\n\r\n const token = params[0];\r\n const url = String.raw(urls, ...params.slice(1));\r\n\r\n return [url, { headers: new HttpHeaders({ 'Custom-Token': token }) }];\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS } from '@angular/common/http';\r\nimport { Observable, of } from 'rxjs';\r\nimport { catchError } from 'rxjs/operators';\r\nimport { Router } from '@angular/router';\r\n\r\n@Injectable()\r\nexport class ErrorInterceptor implements HttpInterceptor {\r\n constructor(private router: Router) {}\r\n\r\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\r\n return next.handle(request).pipe(\r\n catchError((result) => {\r\n if (result.status === 401) {\r\n this.router.navigate(['/errors/401']).then();\r\n }\r\n if (result.error.code) {\r\n return of(result.error);\r\n }\r\n throw result.error.msg ?? result.message;\r\n }),\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 请求错误拦截器\r\n */\r\nexport function providerHttpError() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true };\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS } from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\nimport { shareReplay } from 'rxjs/operators';\r\nimport { RkCacheHttpService } from '@reskin/core/services';\r\n\r\n@Injectable()\r\nexport class CacheInterceptor implements HttpInterceptor {\r\n constructor(private cacheHttp: RkCacheHttpService) {}\r\n\r\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\r\n // 1.判断是GET\r\n // 2.header中添加 Cache-Map: Storage\r\n const cacheMap = request.headers.get('Cache-Map');\r\n if (request.method === 'GET' && cacheMap === 'Storage') {\r\n let response = this.cacheHttp.get(request.url);\r\n if (!response) {\r\n response = next.handle(request).pipe(shareReplay(1));\r\n this.cacheHttp.set(request.url, response);\r\n }\r\n return response;\r\n }\r\n return next.handle(request);\r\n }\r\n}\r\n\r\n/**\r\n * GET请求缓存拦截器\r\n */\r\nexport function providerHttpCache() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true };\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport {\r\n HttpRequest,\r\n HttpHandler,\r\n HttpEvent,\r\n HttpInterceptor,\r\n HttpEventType,\r\n HttpResponse,\r\n HttpErrorResponse,\r\n HTTP_INTERCEPTORS,\r\n} from '@angular/common/http';\r\nimport { Observable, Subscriber } from 'rxjs';\r\nimport { catchError, switchMap } from 'rxjs/operators';\r\n\r\n@Injectable()\r\nexport class BlobInterceptor implements HttpInterceptor {\r\n intercept<T>(request: HttpRequest<T>, next: HttpHandler): Observable<HttpEvent<T>> {\r\n if (request.responseType !== 'blob') {\r\n return next.handle(request);\r\n }\r\n return next.handle(request).pipe(\r\n switchMap((response: HttpEvent<any>) => this.handleBlobResponse(response)),\r\n catchError((response: HttpErrorResponse) => this.handleBlobError(response)),\r\n );\r\n }\r\n\r\n private handleBlobResponse<T>(response: HttpEvent<any>): Observable<HttpEvent<any>> {\r\n if (response.type !== HttpEventType.Response) {\r\n return new Observable((subscriber) => {\r\n subscriber.next(response);\r\n subscriber.complete();\r\n });\r\n }\r\n\r\n if (response instanceof HttpResponse && response.body && response.body.type === 'application/json') {\r\n return new Observable((subscriber) => this.blobToJson<T>(response.body, subscriber));\r\n }\r\n\r\n return new Observable((subscriber) => {\r\n subscriber.next(response);\r\n subscriber.complete();\r\n });\r\n }\r\n\r\n private handleBlobError<T>(response: HttpErrorResponse): Observable<HttpEvent<any>> {\r\n if (response.error && response.error.type === 'application/json') {\r\n return new Observable((subscriber) => this.blobToJson<T>(response.error, subscriber));\r\n }\r\n\r\n return new Observable((subscriber) => {\r\n subscriber.error(response);\r\n subscriber.complete();\r\n });\r\n }\r\n\r\n private blobToJson<T>(blob: Blob, subscriber: Subscriber<HttpEvent<T>>) {\r\n const reader = new FileReader();\r\n reader.addEventListener('loadend', () => {\r\n try {\r\n const json: T = JSON.parse(reader.result as string);\r\n subscriber.error(json);\r\n } catch (error) {\r\n subscriber.error(error);\r\n } finally {\r\n subscriber.complete();\r\n }\r\n });\r\n reader.readAsText(blob, 'utf-8');\r\n }\r\n}\r\n\r\n/**\r\n * 下载文件拦截器\r\n * blob类型的请求会被处理\r\n */\r\nexport function providerDownBlob() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: BlobInterceptor, multi: true };\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"reskin-core-interceptors.js","sources":["../../../library/core/interceptors/types.ts","../../../library/core/interceptors/token.interceptor.ts","../../../library/core/interceptors/error.interceptor.ts","../../../library/core/interceptors/cache.interceptor.ts","../../../library/core/interceptors/blob.interceptor.ts","../../../library/core/interceptors/reskin-core-interceptors.ts"],"sourcesContent":["/**\r\n * HTTP 拦截器相关类型定义\r\n */\r\n\r\n/**\r\n * Token 拦截器配置\r\n */\r\nexport interface TokenInterceptorConfig {\r\n /**\r\n * 默认的 Token Header 名称\r\n * @default 'Authorization'\r\n */\r\n tokenHeaderName?: string;\r\n /**\r\n * 认证 ID Header 名称\r\n * @default 'X-Auth-Id'\r\n */\r\n authIdHeaderName?: string;\r\n}\r\n\r\n/**\r\n * 错误拦截器配置\r\n */\r\nexport interface ErrorInterceptorConfig {\r\n /**\r\n * 401 错误跳转路径\r\n * @default '/errors/401'\r\n */\r\n unauthorizedPath?: string;\r\n /**\r\n * 是否启用错误日志\r\n * @default false\r\n */\r\n enableLogging?: boolean;\r\n /**\r\n * 自定义错误处理函数\r\n */\r\n customErrorHandler?: (error: any) => void;\r\n}\r\n\r\n/**\r\n * 缓存拦截器配置\r\n */\r\nexport interface CacheInterceptorConfig {\r\n /**\r\n * 缓存最大数量\r\n * @default 100\r\n */\r\n maxCacheSize?: number;\r\n /**\r\n * 缓存过期时间(毫秒)\r\n * @default undefined (永不过期)\r\n */\r\n cacheExpiration?: number;\r\n}\r\n\r\n/**\r\n * HTTP 请求选项扩展\r\n */\r\nexport interface HttpRequestOptions {\r\n headers?: { [name: string]: string | string[] };\r\n}\r\n\r\n/**\r\n * Token 控制类型\r\n */\r\nexport type TokenControl = 'no-token' | 'custom-token';\r\n\r\n/**\r\n * 缓存策略类型\r\n */\r\nexport type CacheStrategy = 'Storage' | 'Memory';\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS, HttpHeaders } from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\nimport { RkAuthService } from '@reskin/core/services';\r\nimport { IAuth } from '@reskin/core/entity/user';\r\n\r\n/**\r\n * Token 拦截器常量\r\n */\r\nconst DEFAULT_TOKEN_HEADER_NAME = 'Authorization';\r\nconst TOKEN_CONTROL_HEADER = 'Token-Control';\r\nconst CUSTOM_TOKEN_HEADER = 'Custom-Token';\r\nconst CUSTOM_TOKEN_HEADER_NAME = 'Custom-Token-Header';\r\nconst AUTH_ID_HEADER = 'X-Auth-Id';\r\n\r\n/**\r\n * Token 拦截器\r\n * 自动为 HTTP 请求添加认证 Token\r\n */\r\n@Injectable()\r\nexport class TokenInterceptor implements HttpInterceptor {\r\n constructor(private authService: RkAuthService) {}\r\n\r\n /**\r\n * 拦截 HTTP 请求,添加 Token 认证信息\r\n * @param request HTTP 请求对象\r\n * @param next 下一个拦截器处理器\r\n * @returns Observable<HttpEvent<unknown>>\r\n */\r\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\r\n const tokenControl = request.headers.get(TOKEN_CONTROL_HEADER);\r\n \r\n // 如果明确指定不需要 Token,直接放行\r\n if (tokenControl === 'no-token') {\r\n return next.handle(request);\r\n }\r\n\r\n const customToken = request.headers.get(CUSTOM_TOKEN_HEADER);\r\n const customTokenHeaderName = request.headers.get(CUSTOM_TOKEN_HEADER_NAME) || DEFAULT_TOKEN_HEADER_NAME;\r\n\r\n const headers: { [name: string]: string | string[] } = {};\r\n\r\n if (customToken) {\r\n // 使用自定义 Token\r\n headers[customTokenHeaderName] = customToken;\r\n } else {\r\n // 使用默认认证信息\r\n const auth: IAuth = this.authService.token;\r\n if (auth?.token) {\r\n headers[DEFAULT_TOKEN_HEADER_NAME] = auth.token;\r\n if (auth.id) {\r\n headers[AUTH_ID_HEADER] = auth.id;\r\n }\r\n }\r\n }\r\n\r\n // 如果有需要添加的 Header,克隆请求并添加\r\n if (Object.keys(headers).length > 0) {\r\n request = request.clone({ setHeaders: headers });\r\n }\r\n\r\n return next.handle(request);\r\n }\r\n}\r\n\r\n/**\r\n * 提供 Token 拦截器\r\n * @returns Provider 配置对象\r\n */\r\nexport function providerAuthToken() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true };\r\n}\r\n\r\n/**\r\n * 创建不带 Token 的请求配置\r\n * @param urls 模板字符串数组\r\n * @param params 模板参数\r\n * @returns [url, options] 元组\r\n * @example\r\n * this.http.get(...NoAuthTokenTemplate`/api/public/data`).subscribe();\r\n */\r\nexport function NoAuthTokenTemplate(urls: TemplateStringsArray, ...params: any[]): [string, { headers: HttpHeaders }] {\r\n const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];\r\n return [url, { headers: new HttpHeaders({ [TOKEN_CONTROL_HEADER]: 'no-token' }) }];\r\n}\r\n\r\n/**\r\n * 创建使用自定义 Token 的请求配置\r\n * @param token 自定义 Token 值\r\n * @param urls 模板字符串数组\r\n * @param params 模板参数\r\n * @returns [url, options] 元组\r\n * @example\r\n * this.http.get(...CustomTokenTemplate('my-token', `/api/data`)).subscribe();\r\n */\r\nexport function CustomTokenTemplate(token: string, urls: TemplateStringsArray, ...params: any[]): [string, { headers: HttpHeaders }] {\r\n const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];\r\n return [url, { headers: new HttpHeaders({ [CUSTOM_TOKEN_HEADER]: token }) }];\r\n}\r\n\r\n/**\r\n * 创建使用自定义 Token 和自定义 Header 名称的请求配置\r\n * @param token 自定义 Token 值\r\n * @param headerName 自定义 Header 名称\r\n * @param urls 模板字符串数组\r\n * @param params 模板参数\r\n * @returns [url, options] 元组\r\n * @example\r\n * this.http.get(...CustomTokenWithHeaderTemplate('my-token', 'X-API-Key', `/api/data`)).subscribe();\r\n */\r\nexport function CustomTokenWithHeaderTemplate(\r\n token: string,\r\n headerName: string,\r\n urls: TemplateStringsArray,\r\n ...params: any[]\r\n): [string, { headers: HttpHeaders }] {\r\n const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];\r\n return [\r\n url,\r\n {\r\n headers: new HttpHeaders({\r\n [CUSTOM_TOKEN_HEADER]: token,\r\n [CUSTOM_TOKEN_HEADER_NAME]: headerName,\r\n }),\r\n },\r\n ];\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS, HttpErrorResponse } from '@angular/common/http';\r\nimport { Observable, throwError } from 'rxjs';\r\nimport { catchError } from 'rxjs/operators';\r\nimport { Router } from '@angular/router';\r\nimport { ErrorInterceptorConfig } from './types';\r\n\r\n/**\r\n * 默认配置\r\n */\r\nconst DEFAULT_CONFIG: ErrorInterceptorConfig = {\r\n unauthorizedPath: '/errors/401',\r\n enableLogging: false,\r\n};\r\n\r\n/**\r\n * HTTP 错误拦截器\r\n * 统一处理 HTTP 请求错误,包括 401 未授权错误的自动跳转\r\n */\r\n@Injectable()\r\nexport class ErrorInterceptor implements HttpInterceptor {\r\n private config: ErrorInterceptorConfig = DEFAULT_CONFIG;\r\n\r\n constructor(private router: Router) {}\r\n\r\n /**\r\n * 设置拦截器配置\r\n * @param config 配置对象\r\n */\r\n setConfig(config: ErrorInterceptorConfig): void {\r\n this.config = { ...DEFAULT_CONFIG, ...config };\r\n }\r\n\r\n /**\r\n * 拦截 HTTP 请求,处理错误响应\r\n * @param request HTTP 请求对象\r\n * @param next 下一个拦截器处理器\r\n * @returns Observable<HttpEvent<unknown>>\r\n */\r\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\r\n return next.handle(request).pipe(\r\n catchError((error: HttpErrorResponse) => {\r\n // 处理 401 未授权错误\r\n if (error.status === 401) {\r\n this.handleUnauthorizedError();\r\n return throwError(error);\r\n }\r\n\r\n // 记录错误日志\r\n if (this.config.enableLogging) {\r\n console.error('[HTTP Error]', {\r\n url: request.url,\r\n method: request.method,\r\n status: error.status,\r\n message: error.message,\r\n error: error.error,\r\n });\r\n }\r\n\r\n // 提取错误信息\r\n const errorMessage = this.extractErrorMessage(error);\r\n return throwError(new Error(errorMessage));\r\n }),\r\n );\r\n }\r\n\r\n /**\r\n * 处理 401 未授权错误\r\n */\r\n private handleUnauthorizedError(): void {\r\n const path = this.config.unauthorizedPath || DEFAULT_CONFIG.unauthorizedPath;\r\n this.router.navigate([path]).catch((err) => {\r\n console.error('导航到错误页面失败:', err);\r\n });\r\n }\r\n\r\n /**\r\n * 提取错误信息\r\n * @param error HTTP 错误响应\r\n * @returns 错误信息字符串\r\n */\r\n private extractErrorMessage(error: HttpErrorResponse): string {\r\n if (error.error) {\r\n // 尝试从 error.error 中提取信息\r\n if (typeof error.error === 'string') {\r\n return error.error;\r\n }\r\n if (error.error.msg) {\r\n return error.error.msg;\r\n }\r\n if (error.error.message) {\r\n return error.error.message;\r\n }\r\n }\r\n // 使用默认错误信息\r\n return error.message || `HTTP Error ${error.status}`;\r\n }\r\n}\r\n\r\n/**\r\n * 提供 HTTP 错误拦截器\r\n * @param config 可选的配置对象\r\n * @returns Provider 配置对象\r\n * @example\r\n * providers: [\r\n * providerHttpError({ unauthorizedPath: '/login', enableLogging: true })\r\n * ]\r\n */\r\nexport function providerHttpError(config?: ErrorInterceptorConfig) {\r\n if (config) {\r\n // 如果有配置,使用 useFactory\r\n return {\r\n provide: HTTP_INTERCEPTORS,\r\n useFactory: (router: Router) => {\r\n const interceptor = new ErrorInterceptor(router);\r\n interceptor.setConfig(config);\r\n return interceptor;\r\n },\r\n deps: [Router],\r\n multi: true,\r\n };\r\n } else {\r\n // 没有配置,直接使用 useClass\r\n return {\r\n provide: HTTP_INTERCEPTORS,\r\n useClass: ErrorInterceptor,\r\n multi: true,\r\n };\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS, HttpHeaders } from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\nimport { shareReplay } from 'rxjs/operators';\r\nimport { RkCacheHttpService } from '@reskin/core/services';\r\n\r\n/**\r\n * 缓存策略标识\r\n */\r\nconst CACHE_HEADER = 'Cache-Map';\r\nconst CACHE_STRATEGY = 'Storage';\r\n\r\n/**\r\n * HTTP 缓存拦截器\r\n * 为 GET 请求提供缓存功能,减少重复请求\r\n */\r\n@Injectable()\r\nexport class CacheInterceptor implements HttpInterceptor {\r\n constructor(private cacheHttpService: RkCacheHttpService) {}\r\n\r\n /**\r\n * 拦截 HTTP 请求,实现缓存逻辑\r\n * @param request HTTP 请求对象\r\n * @param next 下一个拦截器处理器\r\n * @returns Observable<HttpEvent<unknown>>\r\n */\r\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\r\n // 只缓存 GET 请求且明确标记了缓存策略的请求\r\n const cacheStrategy = request.headers.get(CACHE_HEADER);\r\n \r\n if (request.method === 'GET' && cacheStrategy === CACHE_STRATEGY) {\r\n // 尝试从缓存中获取响应\r\n let cachedResponse = this.cacheHttpService.get(request.url);\r\n \r\n if (!cachedResponse) {\r\n // 缓存未命中,发起请求并缓存结果\r\n cachedResponse = next.handle(request).pipe(shareReplay(1));\r\n this.cacheHttpService.set(request.url, cachedResponse);\r\n }\r\n \r\n return cachedResponse;\r\n }\r\n\r\n // 非缓存请求,直接放行\r\n return next.handle(request);\r\n }\r\n}\r\n\r\n/**\r\n * 提供 HTTP 缓存拦截器\r\n * @returns Provider 配置对象\r\n * @example\r\n * providers: [providerHttpCache()]\r\n */\r\nexport function providerHttpCache() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true };\r\n}\r\n\r\n/**\r\n * 创建带缓存标记的 GET 请求配置\r\n * @param urls 模板字符串数组\r\n * @param params 模板参数\r\n * @returns [url, options] 元组\r\n * @example\r\n * this.http.get(...CacheHttpTemplate`/api/data`).subscribe();\r\n */\r\nexport function CacheHttpTemplate(urls: TemplateStringsArray, ...params: any[]): [string, { headers: HttpHeaders }] {\r\n const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];\r\n return [url, { headers: new HttpHeaders({ [CACHE_HEADER]: CACHE_STRATEGY }) }];\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport {\r\n HttpRequest,\r\n HttpHandler,\r\n HttpEvent,\r\n HttpInterceptor,\r\n HttpEventType,\r\n HttpResponse,\r\n HttpErrorResponse,\r\n HTTP_INTERCEPTORS,\r\n} from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\nimport { switchMap, catchError } from 'rxjs/operators';\r\n\r\n/**\r\n * Blob 响应拦截器\r\n * 处理文件下载请求中的 JSON 错误响应\r\n */\r\n@Injectable()\r\nexport class BlobInterceptor implements HttpInterceptor {\r\n /**\r\n * 拦截 HTTP 请求,处理 Blob 类型响应\r\n * @param request HTTP 请求对象\r\n * @param next 下一个拦截器处理器\r\n * @returns Observable<HttpEvent<T>>\r\n */\r\n intercept<T>(request: HttpRequest<T>, next: HttpHandler): Observable<HttpEvent<T>> {\r\n // 只处理 responseType 为 blob 的请求\r\n if (request.responseType !== 'blob') {\r\n return next.handle(request);\r\n }\r\n\r\n return next.handle(request).pipe(\r\n switchMap((event: HttpEvent<any>) => this.handleBlobResponse(event)),\r\n catchError((error: HttpErrorResponse) => this.handleBlobError(error)),\r\n );\r\n }\r\n\r\n /**\r\n * 处理 Blob 响应事件\r\n * @param event HTTP 事件\r\n * @returns Observable<HttpEvent<any>>\r\n */\r\n private handleBlobResponse(event: HttpEvent<any>): Observable<HttpEvent<any>> {\r\n // 只处理完整的响应事件\r\n if (event.type !== HttpEventType.Response) {\r\n return new Observable((subscriber) => {\r\n subscriber.next(event);\r\n subscriber.complete();\r\n });\r\n }\r\n\r\n // 检查响应体是否为 JSON 类型(通常表示错误)\r\n if (event instanceof HttpResponse && event.body?.type === 'application/json') {\r\n return this.convertBlobToJson(event.body);\r\n }\r\n\r\n return new Observable((subscriber) => {\r\n subscriber.next(event);\r\n subscriber.complete();\r\n });\r\n }\r\n\r\n /**\r\n * 处理 Blob 错误响应\r\n * @param error HTTP 错误响应\r\n * @returns Observable<HttpEvent<any>>\r\n */\r\n private handleBlobError(error: HttpErrorResponse): Observable<HttpEvent<any>> {\r\n // 如果错误响应体是 JSON 类型的 Blob,转换为 JSON 对象\r\n if (error.error?.type === 'application/json') {\r\n return this.convertBlobToJson(error.error);\r\n }\r\n\r\n return new Observable((subscriber) => {\r\n subscriber.error(error);\r\n subscriber.complete();\r\n });\r\n }\r\n\r\n /**\r\n * 将 Blob 转换为 JSON 对象并抛出错误\r\n * @param blob Blob 对象\r\n * @returns Observable<HttpEvent<T>>\r\n */\r\n private convertBlobToJson<T>(blob: Blob): Observable<HttpEvent<T>> {\r\n return new Observable((subscriber) => {\r\n const reader = new FileReader();\r\n \r\n reader.addEventListener('loadend', () => {\r\n try {\r\n const json: T = JSON.parse(reader.result as string);\r\n subscriber.error(json);\r\n } catch (parseError) {\r\n subscriber.error(parseError);\r\n } finally {\r\n subscriber.complete();\r\n }\r\n });\r\n\r\n reader.addEventListener('error', () => {\r\n subscriber.error(new Error('读取 Blob 数据失败'));\r\n subscriber.complete();\r\n });\r\n\r\n reader.readAsText(blob, 'utf-8');\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * 提供 Blob 响应拦截器\r\n * @returns Provider 配置对象\r\n * @example\r\n * providers: [providerDownBlob()]\r\n */\r\nexport function providerDownBlob() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: BlobInterceptor, multi: true };\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1"],"mappings":"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"}
|