@ahoo-wang/fetcher 0.8.1 → 0.8.2
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/README.md +27 -223
- package/README.zh-CN.md +132 -34
- package/dist/fetchExchange.d.ts +163 -0
- package/dist/fetchExchange.d.ts.map +1 -0
- package/dist/fetchInterceptor.d.ts +2 -1
- package/dist/fetchInterceptor.d.ts.map +1 -1
- package/dist/fetcher.d.ts +22 -86
- package/dist/fetcher.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +127 -89
- package/dist/index.umd.js +1 -1
- package/dist/interceptor.d.ts +6 -79
- package/dist/interceptor.d.ts.map +1 -1
- package/dist/mergeRequest.d.ts +1 -1
- package/dist/mergeRequest.d.ts.map +1 -1
- package/dist/requestBodyInterceptor.d.ts +7 -4
- package/dist/requestBodyInterceptor.d.ts.map +1 -1
- package/dist/urlBuilder.d.ts +3 -0
- package/dist/urlBuilder.d.ts.map +1 -1
- package/dist/urlResolveInterceptor.d.ts +39 -0
- package/dist/urlResolveInterceptor.d.ts.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -106,39 +106,24 @@ const data = await response.json<User>();
|
|
|
106
106
|
|
|
107
107
|
## 🔗 Interceptor System
|
|
108
108
|
|
|
109
|
-
###
|
|
109
|
+
### Core Concepts
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
**Properties:**
|
|
111
|
+
The interceptor system in Fetcher follows the middleware pattern, allowing you to intercept and modify requests,
|
|
112
|
+
responses, and errors at different stages of the HTTP request lifecycle.
|
|
114
113
|
|
|
115
|
-
|
|
116
|
-
- `order: number` - The execution order of the interceptor, smaller values have higher priority
|
|
117
|
-
|
|
118
|
-
**Methods:**
|
|
114
|
+
#### Interceptor Types
|
|
119
115
|
|
|
120
|
-
|
|
116
|
+
1. **Request Interceptors**: Process requests before they are sent
|
|
117
|
+
2. **Response Interceptors**: Process responses after they are received
|
|
118
|
+
3. **Error Interceptors**: Handle errors that occur during the request process
|
|
121
119
|
|
|
122
|
-
|
|
120
|
+
#### Built-in Interceptors
|
|
123
121
|
|
|
124
|
-
|
|
122
|
+
Fetcher comes with several built-in interceptors that are automatically registered:
|
|
125
123
|
|
|
126
|
-
**
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
- `eject(name: string): boolean` - Remove interceptor by name, returns whether the removal was successful
|
|
130
|
-
- `clear(): void` - Clear all interceptors
|
|
131
|
-
- `intercept(exchange: FetchExchange): Promise<FetchExchange>` - Execute all interceptors in sequence
|
|
132
|
-
|
|
133
|
-
### FetcherInterceptors
|
|
134
|
-
|
|
135
|
-
Fetcher interceptor collection, including request, response, and error interceptor managers.
|
|
136
|
-
|
|
137
|
-
**Properties:**
|
|
138
|
-
|
|
139
|
-
- `request: InterceptorManager` - Request interceptor manager
|
|
140
|
-
- `response: InterceptorManager` - Response interceptor manager
|
|
141
|
-
- `error: InterceptorManager` - Error interceptor manager
|
|
124
|
+
1. **UrlResolveInterceptor**: Resolves URLs with path and query parameters (order: Number.MIN_SAFE_INTEGER)
|
|
125
|
+
2. **RequestBodyInterceptor**: Converts object bodies to JSON strings (order: Number.MIN_SAFE_INTEGER + 100)
|
|
126
|
+
3. **FetchInterceptor**: Executes the actual HTTP request (order: Number.MAX_SAFE_INTEGER)
|
|
142
127
|
|
|
143
128
|
### Using Interceptors
|
|
144
129
|
|
|
@@ -245,34 +230,6 @@ fetcher.interceptors.request.use({
|
|
|
245
230
|
// 3. auth-interceptor (order: 50)
|
|
246
231
|
```
|
|
247
232
|
|
|
248
|
-
### Response Interceptors
|
|
249
|
-
|
|
250
|
-
```typescript
|
|
251
|
-
// Add response interceptor (e.g., for logging)
|
|
252
|
-
fetcher.interceptors.response.use({
|
|
253
|
-
intercept(exchange) {
|
|
254
|
-
console.log('Response received:', exchange.response.status);
|
|
255
|
-
return exchange;
|
|
256
|
-
},
|
|
257
|
-
});
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
### Error Interceptors
|
|
261
|
-
|
|
262
|
-
```typescript
|
|
263
|
-
// Add error interceptor (e.g., for unified error handling)
|
|
264
|
-
fetcher.interceptors.error.use({
|
|
265
|
-
intercept(exchange) {
|
|
266
|
-
if (exchange.error?.name === 'FetchTimeoutError') {
|
|
267
|
-
console.error('Request timeout:', exchange.error.message);
|
|
268
|
-
} else {
|
|
269
|
-
console.error('Network error:', exchange.error?.message);
|
|
270
|
-
}
|
|
271
|
-
return exchange;
|
|
272
|
-
},
|
|
273
|
-
});
|
|
274
|
-
```
|
|
275
|
-
|
|
276
233
|
## 📚 API Reference
|
|
277
234
|
|
|
278
235
|
### Fetcher Class
|
|
@@ -290,6 +247,7 @@ new Fetcher(options ? : FetcherOptions);
|
|
|
290
247
|
- `baseURL`: Base URL for all requests
|
|
291
248
|
- `timeout`: Request timeout in milliseconds
|
|
292
249
|
- `headers`: Default request headers
|
|
250
|
+
- `interceptors`: Interceptor collection for request, response, and error handling
|
|
293
251
|
|
|
294
252
|
#### Methods
|
|
295
253
|
|
|
@@ -302,98 +260,25 @@ new Fetcher(options ? : FetcherOptions);
|
|
|
302
260
|
- `head(url: string, request?: Omit<FetcherRequest, 'method' | 'body'>): Promise<Response>` - HEAD request
|
|
303
261
|
- `options(url: string, request?: Omit<FetcherRequest, 'method' | 'body'>): Promise<Response>` - OPTIONS request
|
|
304
262
|
|
|
305
|
-
### Response Extension
|
|
306
|
-
|
|
307
|
-
To provide better TypeScript support, we extend the native Response interface with a type-safe json() method:
|
|
308
|
-
|
|
309
|
-
```typescript
|
|
310
|
-
// Now you can use it with type safety
|
|
311
|
-
const response = await fetcher.get('/users/123');
|
|
312
|
-
const userData = await response.json<User>(); // Type is Promise<User>
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
### NamedFetcher Class
|
|
316
|
-
|
|
317
|
-
An extension of the Fetcher class that automatically registers itself with the global fetcherRegistrar.
|
|
318
|
-
|
|
319
|
-
#### Constructor
|
|
320
|
-
|
|
321
|
-
```typescript
|
|
322
|
-
new NamedFetcher(name
|
|
323
|
-
:
|
|
324
|
-
string, options ? : FetcherOptions
|
|
325
|
-
)
|
|
326
|
-
;
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
### FetcherRegistrar
|
|
330
|
-
|
|
331
|
-
Global instance for managing multiple Fetcher instances by name.
|
|
332
|
-
|
|
333
263
|
#### Properties
|
|
334
264
|
|
|
335
|
-
- `
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
- `register(name: string, fetcher: Fetcher): void` - Register a fetcher with a name
|
|
340
|
-
- `unregister(name: string): boolean` - Unregister a fetcher by name
|
|
341
|
-
- `get(name: string): Fetcher | undefined` - Get a fetcher by name
|
|
342
|
-
- `requiredGet(name: string): Fetcher` - Get a fetcher by name, throws if not found
|
|
343
|
-
- `fetchers: Map<string, Fetcher>` - Get all registered fetchers
|
|
344
|
-
|
|
345
|
-
### Interceptor System
|
|
346
|
-
|
|
347
|
-
#### Interceptor
|
|
348
|
-
|
|
349
|
-
Interceptor interface that defines the basic structure of interceptors.
|
|
350
|
-
|
|
351
|
-
**Properties:**
|
|
352
|
-
|
|
353
|
-
- `name: string` - The name of the interceptor, used to identify it, must be unique
|
|
354
|
-
- `order: number` - The execution order of the interceptor, smaller values have higher priority
|
|
355
|
-
|
|
356
|
-
**Methods:**
|
|
357
|
-
|
|
358
|
-
- `intercept(exchange: FetchExchange): FetchExchange | Promise<FetchExchange>` - Intercept and process data
|
|
359
|
-
|
|
360
|
-
#### InterceptorManager
|
|
361
|
-
|
|
362
|
-
Interceptor manager for managing multiple interceptors of the same type.
|
|
363
|
-
|
|
364
|
-
**Methods:**
|
|
365
|
-
|
|
366
|
-
- `use(interceptor: Interceptor): boolean` - Add interceptor, returns whether the addition was successful
|
|
367
|
-
- `eject(name: string): boolean` - Remove interceptor by name, returns whether the removal was successful
|
|
368
|
-
- `clear(): void` - Clear all interceptors
|
|
369
|
-
- `intercept(exchange: FetchExchange): Promise<FetchExchange>` - Execute all interceptors in sequence
|
|
265
|
+
- `urlBuilder`: URL builder instance for constructing URLs
|
|
266
|
+
- `headers`: Default request headers
|
|
267
|
+
- `timeout`: Default request timeout
|
|
268
|
+
- `interceptors`: Interceptor collection for request, response, and error handling
|
|
370
269
|
|
|
371
|
-
|
|
270
|
+
### FetcherRequest Interface
|
|
372
271
|
|
|
373
|
-
|
|
272
|
+
Configuration options for HTTP requests.
|
|
374
273
|
|
|
375
274
|
**Properties:**
|
|
376
275
|
|
|
377
|
-
- `
|
|
378
|
-
- `
|
|
379
|
-
- `
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
- `baseURL`: Base URL for all requests
|
|
276
|
+
- `method`: HTTP method (GET, POST, PUT, DELETE, etc.)
|
|
277
|
+
- `headers`: Request headers
|
|
278
|
+
- `body`: Request body (can be object, string, Blob, etc.)
|
|
279
|
+
- `path`: Path parameters for URL templating
|
|
280
|
+
- `query`: Query parameters for URL query string
|
|
384
281
|
- `timeout`: Request timeout in milliseconds
|
|
385
|
-
- `headers`: Default request headers
|
|
386
|
-
|
|
387
|
-
#### Methods
|
|
388
|
-
|
|
389
|
-
- `fetch(url: string, request?: FetcherRequest): Promise<Response>` - Generic HTTP request method
|
|
390
|
-
- `get(url: string, request?: Omit<FetcherRequest, 'method' | 'body'>): Promise<Response>` - GET request
|
|
391
|
-
- `post(url: string, request?: Omit<FetcherRequest, 'method'>): Promise<Response>` - POST request
|
|
392
|
-
- `put(url: string, request?: Omit<FetcherRequest, 'method'>): Promise<Response>` - PUT request
|
|
393
|
-
- `delete(url: string, request?: Omit<FetcherRequest, 'method'>): Promise<Response>` - DELETE request
|
|
394
|
-
- `patch(url: string, request?: Omit<FetcherRequest, 'method'>): Promise<Response>` - PATCH request
|
|
395
|
-
- `head(url: string, request?: Omit<FetcherRequest, 'method' | 'body'>): Promise<Response>` - HEAD request
|
|
396
|
-
- `options(url: string, request?: Omit<FetcherRequest, 'method' | 'body'>): Promise<Response>` - OPTIONS request
|
|
397
282
|
|
|
398
283
|
### Response Extension
|
|
399
284
|
|
|
@@ -437,7 +322,7 @@ Global instance for managing multiple Fetcher instances by name.
|
|
|
437
322
|
|
|
438
323
|
### Interceptor System
|
|
439
324
|
|
|
440
|
-
#### Interceptor
|
|
325
|
+
#### Interceptor Interface
|
|
441
326
|
|
|
442
327
|
Interceptor interface that defines the basic structure of interceptors.
|
|
443
328
|
|
|
@@ -450,7 +335,7 @@ Interceptor interface that defines the basic structure of interceptors.
|
|
|
450
335
|
|
|
451
336
|
- `intercept(exchange: FetchExchange): FetchExchange | Promise<FetchExchange>` - Intercept and process data
|
|
452
337
|
|
|
453
|
-
#### InterceptorManager
|
|
338
|
+
#### InterceptorManager Class
|
|
454
339
|
|
|
455
340
|
Interceptor manager for managing multiple interceptors of the same type.
|
|
456
341
|
|
|
@@ -461,7 +346,7 @@ Interceptor manager for managing multiple interceptors of the same type.
|
|
|
461
346
|
- `clear(): void` - Clear all interceptors
|
|
462
347
|
- `intercept(exchange: FetchExchange): Promise<FetchExchange>` - Execute all interceptors in sequence
|
|
463
348
|
|
|
464
|
-
#### FetcherInterceptors
|
|
349
|
+
#### FetcherInterceptors Class
|
|
465
350
|
|
|
466
351
|
Fetcher interceptor collection, including request, response, and error interceptor managers.
|
|
467
352
|
|
|
@@ -471,87 +356,6 @@ Fetcher interceptor collection, including request, response, and error intercept
|
|
|
471
356
|
- `response: InterceptorManager` - Response interceptor manager
|
|
472
357
|
- `error: InterceptorManager` - Error interceptor manager
|
|
473
358
|
|
|
474
|
-
#### Request Interceptors
|
|
475
|
-
|
|
476
|
-
```typescript
|
|
477
|
-
import { Fetcher } from '@ahoo-wang/fetcher';
|
|
478
|
-
|
|
479
|
-
const fetcher = new Fetcher({ baseURL: 'https://api.example.com' });
|
|
480
|
-
|
|
481
|
-
// Add request interceptor (e.g., for authentication)
|
|
482
|
-
const success = fetcher.interceptors.request.use({
|
|
483
|
-
name: 'auth-interceptor',
|
|
484
|
-
order: 100,
|
|
485
|
-
intercept(exchange) {
|
|
486
|
-
return {
|
|
487
|
-
...exchange,
|
|
488
|
-
request: {
|
|
489
|
-
...exchange.request,
|
|
490
|
-
headers: {
|
|
491
|
-
...exchange.request.headers,
|
|
492
|
-
Authorization: 'Bearer ' + getAuthToken(),
|
|
493
|
-
},
|
|
494
|
-
},
|
|
495
|
-
};
|
|
496
|
-
},
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
// Remove interceptor
|
|
500
|
-
fetcher.interceptors.request.eject('auth-interceptor');
|
|
501
|
-
```
|
|
502
|
-
|
|
503
|
-
### OrderedCapable System
|
|
504
|
-
|
|
505
|
-
The `OrderedCapable` system allows you to control the execution order of interceptors and other components.
|
|
506
|
-
|
|
507
|
-
#### Ordering Concept
|
|
508
|
-
|
|
509
|
-
```typescript
|
|
510
|
-
import { OrderedCapable } from '@ahoo-wang/fetcher';
|
|
511
|
-
|
|
512
|
-
// Lower order values have higher priority
|
|
513
|
-
const highPriority: OrderedCapable = { order: 1 }; // Executes first
|
|
514
|
-
const mediumPriority: OrderedCapable = { order: 10 }; // Executes second
|
|
515
|
-
const lowPriority: OrderedCapable = { order: 100 }; // Executes last
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
#### Interceptor Ordering
|
|
519
|
-
|
|
520
|
-
```typescript
|
|
521
|
-
// Add interceptors with different orders
|
|
522
|
-
fetcher.interceptors.request.use({
|
|
523
|
-
name: 'logging-interceptor',
|
|
524
|
-
order: 10, // Executes early
|
|
525
|
-
intercept(exchange) {
|
|
526
|
-
console.log('Early logging');
|
|
527
|
-
return exchange;
|
|
528
|
-
},
|
|
529
|
-
});
|
|
530
|
-
|
|
531
|
-
fetcher.interceptors.request.use({
|
|
532
|
-
name: 'auth-interceptor',
|
|
533
|
-
order: 50, // Executes later
|
|
534
|
-
intercept(exchange) {
|
|
535
|
-
// Add auth headers
|
|
536
|
-
return exchange;
|
|
537
|
-
},
|
|
538
|
-
});
|
|
539
|
-
|
|
540
|
-
fetcher.interceptors.request.use({
|
|
541
|
-
name: 'timing-interceptor',
|
|
542
|
-
order: 5, // Executes very early
|
|
543
|
-
intercept(exchange) {
|
|
544
|
-
console.log('Very early timing');
|
|
545
|
-
return exchange;
|
|
546
|
-
},
|
|
547
|
-
});
|
|
548
|
-
|
|
549
|
-
// Execution order will be:
|
|
550
|
-
// 1. timing-interceptor (order: 5)
|
|
551
|
-
// 2. logging-interceptor (order: 10)
|
|
552
|
-
// 3. auth-interceptor (order: 50)
|
|
553
|
-
```
|
|
554
|
-
|
|
555
359
|
## 🤝 Contributing
|
|
556
360
|
|
|
557
361
|
Contributions are welcome! Please see
|
package/README.zh-CN.md
CHANGED
|
@@ -105,39 +105,23 @@ const data = await response.json<User>();
|
|
|
105
105
|
|
|
106
106
|
## 🔗 拦截器系统
|
|
107
107
|
|
|
108
|
-
###
|
|
108
|
+
### 核心概念
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
**属性:**
|
|
113
|
-
|
|
114
|
-
- `name: string` - 拦截器的名称,用于标识拦截器,不可重复
|
|
115
|
-
- `order: number` - 拦截器的执行顺序,数值越小优先级越高
|
|
116
|
-
|
|
117
|
-
**方法:**
|
|
118
|
-
|
|
119
|
-
- `intercept(exchange: FetchExchange): FetchExchange | Promise<FetchExchange>` - 拦截并处理数据
|
|
120
|
-
|
|
121
|
-
### InterceptorManager
|
|
110
|
+
Fetcher 中的拦截器系统遵循中间件模式,允许您在 HTTP 请求生命周期的不同阶段拦截和修改请求、响应和错误。
|
|
122
111
|
|
|
123
|
-
|
|
112
|
+
#### 拦截器类型
|
|
124
113
|
|
|
125
|
-
|
|
114
|
+
1. **请求拦截器**:在发送请求之前处理请求
|
|
115
|
+
2. **响应拦截器**:在收到响应之后处理响应
|
|
116
|
+
3. **错误拦截器**:处理请求过程中发生的错误
|
|
126
117
|
|
|
127
|
-
|
|
128
|
-
- `eject(name: string): boolean` - 按名称移除拦截器,返回是否移除成功
|
|
129
|
-
- `clear(): void` - 清除所有拦截器
|
|
130
|
-
- `intercept(exchange: FetchExchange): Promise<FetchExchange>` - 顺序执行所有拦截器
|
|
118
|
+
#### 内置拦截器
|
|
131
119
|
|
|
132
|
-
|
|
120
|
+
Fetcher 自带几个内置拦截器,它们会自动注册:
|
|
133
121
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
- `request: InterceptorManager` - 请求拦截器管理器
|
|
139
|
-
- `response: InterceptorManager` - 响应拦截器管理器
|
|
140
|
-
- `error: InterceptorManager` - 错误拦截器管理器
|
|
122
|
+
1. **UrlResolveInterceptor**:解析带路径和查询参数的 URL(顺序:Number.MIN_SAFE_INTEGER)
|
|
123
|
+
2. **RequestBodyInterceptor**:将对象体转换为 JSON 字符串(顺序:Number.MIN_SAFE_INTEGER + 100)
|
|
124
|
+
3. **FetchInterceptor**:执行实际的 HTTP 请求(顺序:Number.MAX_SAFE_INTEGER)
|
|
141
125
|
|
|
142
126
|
### 使用拦截器
|
|
143
127
|
|
|
@@ -244,18 +228,132 @@ fetcher.interceptors.request.use({
|
|
|
244
228
|
// 3. auth-interceptor (order: 50)
|
|
245
229
|
```
|
|
246
230
|
|
|
247
|
-
##
|
|
231
|
+
## 📚 API 参考
|
|
248
232
|
|
|
249
|
-
###
|
|
233
|
+
### Fetcher 类
|
|
250
234
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
235
|
+
核心 HTTP 客户端类,提供各种 HTTP 方法。
|
|
236
|
+
|
|
237
|
+
#### 构造函数
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
new Fetcher(options ? : FetcherOptions);
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**选项:**
|
|
244
|
+
|
|
245
|
+
- `baseURL`:所有请求的基础 URL
|
|
246
|
+
- `timeout`:请求超时时间(毫秒)
|
|
247
|
+
- `headers`:默认请求头部
|
|
248
|
+
- `interceptors`:用于请求、响应和错误处理的拦截器集合
|
|
249
|
+
|
|
250
|
+
#### 方法
|
|
251
|
+
|
|
252
|
+
- `fetch(url: string, request?: FetcherRequest): Promise<Response>` - 通用 HTTP 请求方法
|
|
253
|
+
- `get(url: string, request?: Omit<FetcherRequest, 'method' | 'body'>): Promise<Response>` - GET 请求
|
|
254
|
+
- `post(url: string, request?: Omit<FetcherRequest, 'method'>): Promise<Response>` - POST 请求
|
|
255
|
+
- `put(url: string, request?: Omit<FetcherRequest, 'method'>): Promise<Response>` - PUT 请求
|
|
256
|
+
- `delete(url: string, request?: Omit<FetcherRequest, 'method'>): Promise<Response>` - DELETE 请求
|
|
257
|
+
- `patch(url: string, request?: Omit<FetcherRequest, 'method'>): Promise<Response>` - PATCH 请求
|
|
258
|
+
- `head(url: string, request?: Omit<FetcherRequest, 'method' | 'body'>): Promise<Response>` - HEAD 请求
|
|
259
|
+
- `options(url: string, request?: Omit<FetcherRequest, 'method' | 'body'>): Promise<Response>` - OPTIONS 请求
|
|
254
260
|
|
|
255
|
-
|
|
256
|
-
|
|
261
|
+
#### 属性
|
|
262
|
+
|
|
263
|
+
- `urlBuilder`:用于构建 URL 的 URL 构建器实例
|
|
264
|
+
- `headers`:默认请求头部
|
|
265
|
+
- `timeout`:默认请求超时时间
|
|
266
|
+
- `interceptors`:用于请求、响应和错误处理的拦截器集合
|
|
267
|
+
|
|
268
|
+
### FetcherRequest 接口
|
|
269
|
+
|
|
270
|
+
HTTP 请求的配置选项。
|
|
271
|
+
|
|
272
|
+
**属性:**
|
|
273
|
+
|
|
274
|
+
- `method`:HTTP 方法(GET、POST、PUT、DELETE 等)
|
|
275
|
+
- `headers`:请求头部
|
|
276
|
+
- `body`:请求体(可以是对象、字符串、Blob 等)
|
|
277
|
+
- `path`:用于 URL 模板的路径参数
|
|
278
|
+
- `query`:用于 URL 查询字符串的查询参数
|
|
279
|
+
- `timeout`:请求超时时间(毫秒)
|
|
280
|
+
|
|
281
|
+
### 响应扩展
|
|
282
|
+
|
|
283
|
+
为了提供更好的 TypeScript 支持,我们扩展了原生 Response 接口,添加了类型安全的 json() 方法:
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
// 现在您可以安全地使用它
|
|
287
|
+
const response = await fetcher.get('/users/123');
|
|
288
|
+
const userData = await response.json<User>(); // 类型是 Promise<User>
|
|
257
289
|
```
|
|
258
290
|
|
|
291
|
+
### NamedFetcher 类
|
|
292
|
+
|
|
293
|
+
Fetcher 类的扩展,会自动将自己注册到全局 fetcherRegistrar。
|
|
294
|
+
|
|
295
|
+
#### 构造函数
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
new NamedFetcher(name
|
|
299
|
+
:
|
|
300
|
+
string, options ? : FetcherOptions
|
|
301
|
+
)
|
|
302
|
+
;
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### FetcherRegistrar
|
|
306
|
+
|
|
307
|
+
用于按名称管理多个 Fetcher 实例的全局实例。
|
|
308
|
+
|
|
309
|
+
#### 属性
|
|
310
|
+
|
|
311
|
+
- `default`:获取或设置默认 fetcher 实例
|
|
312
|
+
|
|
313
|
+
#### 方法
|
|
314
|
+
|
|
315
|
+
- `register(name: string, fetcher: Fetcher): void` - 按名称注册 fetcher
|
|
316
|
+
- `unregister(name: string): boolean` - 按名称注销 fetcher
|
|
317
|
+
- `get(name: string): Fetcher | undefined` - 按名称获取 fetcher
|
|
318
|
+
- `requiredGet(name: string): Fetcher` - 按名称获取 fetcher,如果未找到则抛出错误
|
|
319
|
+
- `fetchers: Map<string, Fetcher>` - 获取所有已注册的 fetcher
|
|
320
|
+
|
|
321
|
+
### 拦截器系统
|
|
322
|
+
|
|
323
|
+
#### Interceptor 接口
|
|
324
|
+
|
|
325
|
+
拦截器接口,定义了拦截器的基本结构。
|
|
326
|
+
|
|
327
|
+
**属性:**
|
|
328
|
+
|
|
329
|
+
- `name: string` - 拦截器的名称,用于标识拦截器,不可重复
|
|
330
|
+
- `order: number` - 拦截器的执行顺序,数值越小优先级越高
|
|
331
|
+
|
|
332
|
+
**方法:**
|
|
333
|
+
|
|
334
|
+
- `intercept(exchange: FetchExchange): FetchExchange | Promise<FetchExchange>` - 拦截并处理数据
|
|
335
|
+
|
|
336
|
+
#### InterceptorManager 类
|
|
337
|
+
|
|
338
|
+
用于管理同一类型多个拦截器的拦截器管理器。
|
|
339
|
+
|
|
340
|
+
**方法:**
|
|
341
|
+
|
|
342
|
+
- `use(interceptor: Interceptor): boolean` - 添加拦截器,返回是否添加成功
|
|
343
|
+
- `eject(name: string): boolean` - 按名称移除拦截器,返回是否移除成功
|
|
344
|
+
- `clear(): void` - 清除所有拦截器
|
|
345
|
+
- `intercept(exchange: FetchExchange): Promise<FetchExchange>` - 顺序执行所有拦截器
|
|
346
|
+
|
|
347
|
+
#### FetcherInterceptors 类
|
|
348
|
+
|
|
349
|
+
Fetcher 拦截器集合,包括请求、响应和错误拦截器管理器。
|
|
350
|
+
|
|
351
|
+
**属性:**
|
|
352
|
+
|
|
353
|
+
- `request: InterceptorManager` - 请求拦截器管理器
|
|
354
|
+
- `response: InterceptorManager` - 响应拦截器管理器
|
|
355
|
+
- `error: InterceptorManager` - 错误拦截器管理器
|
|
356
|
+
|
|
259
357
|
## 🤝 贡献
|
|
260
358
|
|
|
261
359
|
欢迎贡献!请查看 [贡献指南](https://github.com/Ahoo-Wang/fetcher/blob/main/CONTRIBUTING.md) 了解更多详情。
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { Fetcher } from './fetcher';
|
|
2
|
+
import { HeadersCapable } from './types';
|
|
3
|
+
import { TimeoutCapable } from './timeout';
|
|
4
|
+
/**
|
|
5
|
+
* Fetcher request configuration interface
|
|
6
|
+
*
|
|
7
|
+
* This interface defines all the configuration options available for making HTTP requests
|
|
8
|
+
* with the Fetcher client. It extends the standard RequestInit interface while adding
|
|
9
|
+
* Fetcher-specific features like path parameters, query parameters, and timeout control.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const request: FetcherRequest = {
|
|
14
|
+
* method: 'GET',
|
|
15
|
+
* path: { id: 123 },
|
|
16
|
+
* query: { include: 'profile' },
|
|
17
|
+
* headers: { 'Authorization': 'Bearer token' },
|
|
18
|
+
* timeout: 5000
|
|
19
|
+
* };
|
|
20
|
+
*
|
|
21
|
+
* const response = await fetcher.fetch('/users/{id}', request);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export interface FetcherRequest extends TimeoutCapable, HeadersCapable, Omit<RequestInit, 'body' | 'headers'> {
|
|
25
|
+
/**
|
|
26
|
+
* Path parameters for URL templating
|
|
27
|
+
*
|
|
28
|
+
* An object containing key-value pairs that will be used to replace placeholders
|
|
29
|
+
* in the URL path. Placeholders are specified using curly braces, e.g., '/users/{id}'.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* // With URL '/users/{id}/posts/{postId}'
|
|
34
|
+
* const request = {
|
|
35
|
+
* path: { id: 123, postId: 456 }
|
|
36
|
+
* };
|
|
37
|
+
* // Results in URL: '/users/123/posts/456'
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
path?: Record<string, any>;
|
|
41
|
+
/**
|
|
42
|
+
* Query parameters for URL query string
|
|
43
|
+
*
|
|
44
|
+
* An object containing key-value pairs that will be serialized and appended
|
|
45
|
+
* to the URL as query parameters. Arrays are serialized as multiple parameters
|
|
46
|
+
* with the same name, and objects are JSON-stringified.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const request = {
|
|
51
|
+
* query: {
|
|
52
|
+
* limit: 10,
|
|
53
|
+
* filter: 'active',
|
|
54
|
+
* tags: ['important', 'urgent']
|
|
55
|
+
* }
|
|
56
|
+
* };
|
|
57
|
+
* // Results in query string: '?limit=10&filter=active&tags=important&tags=urgent'
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
query?: Record<string, any>;
|
|
61
|
+
/**
|
|
62
|
+
* Request body
|
|
63
|
+
*
|
|
64
|
+
* The body of the request. Can be a string, Blob, ArrayBuffer, FormData,
|
|
65
|
+
* URLSearchParams, or a plain object. Plain objects are automatically
|
|
66
|
+
* converted to JSON and the appropriate Content-Type header is set.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* // Plain object (automatically converted to JSON)
|
|
71
|
+
* const request = {
|
|
72
|
+
* method: 'POST',
|
|
73
|
+
* body: { name: 'John', email: 'john@example.com' }
|
|
74
|
+
* };
|
|
75
|
+
*
|
|
76
|
+
* // FormData
|
|
77
|
+
* const formData = new FormData();
|
|
78
|
+
* formData.append('name', 'John');
|
|
79
|
+
* const request = {
|
|
80
|
+
* method: 'POST',
|
|
81
|
+
* body: formData
|
|
82
|
+
* };
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
body?: BodyInit | Record<string, any> | null;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* FetchExchange Interface
|
|
89
|
+
*
|
|
90
|
+
* Represents the complete exchange object that flows through the interceptor chain.
|
|
91
|
+
* This object contains all the information about a request, response, and any errors
|
|
92
|
+
* that occur during the HTTP request lifecycle. It also provides a mechanism for
|
|
93
|
+
* sharing data between interceptors through the attributes property.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* // In a request interceptor
|
|
98
|
+
* const requestInterceptor: Interceptor = {
|
|
99
|
+
* name: 'RequestInterceptor',
|
|
100
|
+
* order: 0,
|
|
101
|
+
* async intercept(exchange: FetchExchange): Promise<FetchExchange> {
|
|
102
|
+
* // Add custom data to share with other interceptors
|
|
103
|
+
* exchange.attributes = exchange.attributes || {};
|
|
104
|
+
* exchange.attributes.startTime = Date.now();
|
|
105
|
+
* exchange.attributes.customHeader = 'my-value';
|
|
106
|
+
* return exchange;
|
|
107
|
+
* }
|
|
108
|
+
* };
|
|
109
|
+
*
|
|
110
|
+
* // In a response interceptor
|
|
111
|
+
* const responseInterceptor: Interceptor = {
|
|
112
|
+
* name: 'ResponseInterceptor',
|
|
113
|
+
* order: 0,
|
|
114
|
+
* async intercept(exchange: FetchExchange): Promise<FetchExchange> {
|
|
115
|
+
* // Access data shared by previous interceptors
|
|
116
|
+
* if (exchange.attributes && exchange.attributes.startTime) {
|
|
117
|
+
* const startTime = exchange.attributes.startTime;
|
|
118
|
+
* const duration = Date.now() - startTime;
|
|
119
|
+
* console.log(`Request took ${duration}ms`);
|
|
120
|
+
* }
|
|
121
|
+
* return exchange;
|
|
122
|
+
* }
|
|
123
|
+
* };
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export interface FetchExchange {
|
|
127
|
+
/**
|
|
128
|
+
* The Fetcher instance that initiated this exchange
|
|
129
|
+
*/
|
|
130
|
+
fetcher: Fetcher;
|
|
131
|
+
/**
|
|
132
|
+
* The URL for this request
|
|
133
|
+
*/
|
|
134
|
+
url: string;
|
|
135
|
+
/**
|
|
136
|
+
* The request configuration including method, headers, body, etc.
|
|
137
|
+
*/
|
|
138
|
+
request: FetcherRequest;
|
|
139
|
+
/**
|
|
140
|
+
* The response object, undefined until the request completes successfully
|
|
141
|
+
*/
|
|
142
|
+
response: Response | undefined;
|
|
143
|
+
/**
|
|
144
|
+
* Any error that occurred during the request processing, undefined if no error occurred
|
|
145
|
+
*/
|
|
146
|
+
error: Error | any | undefined;
|
|
147
|
+
/**
|
|
148
|
+
* Shared attributes for passing data between interceptors
|
|
149
|
+
*
|
|
150
|
+
* This property allows interceptors to share arbitrary data with each other.
|
|
151
|
+
* Interceptors can read from and write to this object to pass information
|
|
152
|
+
* along the interceptor chain.
|
|
153
|
+
*
|
|
154
|
+
* @remarks
|
|
155
|
+
* - This property is optional and may be undefined initially
|
|
156
|
+
* - Interceptors should initialize this property if they need to use it
|
|
157
|
+
* - Use string keys to avoid conflicts between different interceptors
|
|
158
|
+
* - Consider namespacing your keys (e.g., 'mylib.retryCount' instead of 'retryCount')
|
|
159
|
+
* - Be mindful of memory usage when storing large objects
|
|
160
|
+
*/
|
|
161
|
+
attributes?: Record<string, any>;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=fetchExchange.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetchExchange.d.ts","sourceRoot":"","sources":["../src/fetchExchange.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,cACf,SAAQ,cAAc,EACpB,cAAc,EACd,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC;;;;;;;;;;;;;;OAcG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE3B;;;;;;;;;;;;;;;;;;OAkBG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE5B;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,OAAO,EAAE,cAAc,CAAC;IAExB;;OAEG;IACH,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC;IAE/B;;OAEG;IACH,KAAK,EAAE,KAAK,GAAG,GAAG,GAAG,SAAS,CAAC;IAE/B;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAClC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchInterceptor.d.ts","sourceRoot":"","sources":["../src/fetchInterceptor.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"fetchInterceptor.d.ts","sourceRoot":"","sources":["../src/fetchInterceptor.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;;;;;;;;;;GAYG;AACH,qBAAa,gBAAiB,YAAW,WAAW;IAClD;;;;;;OAMG;IACH,IAAI,SAAsB;IAE1B;;;;;;;OAOG;IACH,KAAK,SAA2B;IAEhC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;CAQjE"}
|