@lytjs/common-http 6.5.0 → 6.6.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/README.md +257 -0
- package/dist/index.cjs +68 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +49 -2
- package/dist/index.d.ts +49 -2
- package/dist/index.mjs +58 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +38 -35
- package/src/index.ts +481 -334
package/README.md
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# @lytjs/common-http
|
|
2
|
+
|
|
3
|
+
基于原生 `fetch` API 的轻量级 HTTP 客户端,支持拦截器、超时、数组查询参数等功能。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @lytjs/common-http
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 快速开始
|
|
12
|
+
|
|
13
|
+
### 基础使用
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { http, getJson, postJson } from '@lytjs/common-http';
|
|
17
|
+
|
|
18
|
+
// 使用默认 http 实例发送请求
|
|
19
|
+
const response = await http.get('/api/users');
|
|
20
|
+
console.log(response.data);
|
|
21
|
+
|
|
22
|
+
// 或使用便捷的 JSON 方法
|
|
23
|
+
const data = await getJson('/api/users');
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 创建自定义客户端
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { createHttpClient } from '@lytjs/common-http';
|
|
30
|
+
|
|
31
|
+
const apiClient = createHttpClient({
|
|
32
|
+
baseURL: 'https://api.example.com',
|
|
33
|
+
headers: {
|
|
34
|
+
Authorization: 'Bearer YOUR_TOKEN',
|
|
35
|
+
'Content-Type': 'application/json',
|
|
36
|
+
},
|
|
37
|
+
timeout: 5000,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const users = await apiClient.get('/users');
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## API
|
|
44
|
+
|
|
45
|
+
### 便捷方法
|
|
46
|
+
|
|
47
|
+
| 方法 | 说明 |
|
|
48
|
+
| ------------------------------------ | ------------------------------------ |
|
|
49
|
+
| `get<T>(url, options?)` | 发送 GET 请求 |
|
|
50
|
+
| `post<T>(url, data?, options?)` | 发送 POST 请求 |
|
|
51
|
+
| `put<T>(url, data?, options?)` | 发送 PUT 请求 |
|
|
52
|
+
| `patch<T>(url, data?, options?)` | 发送 PATCH 请求 |
|
|
53
|
+
| `del<T>(url, options?)` | 发送 DELETE 请求 |
|
|
54
|
+
| `getJson<T>(url, options?)` | 发送 GET 请求并直接返回 JSON 数据 |
|
|
55
|
+
| `postJson<T>(url, data?, options?)` | 发送 POST 请求并直接返回 JSON 数据 |
|
|
56
|
+
| `putJson<T>(url, data?, options?)` | 发送 PUT 请求并直接返回 JSON 数据 |
|
|
57
|
+
| `patchJson<T>(url, data?, options?)` | 发送 PATCH 请求并直接返回 JSON 数据 |
|
|
58
|
+
| `deleteJson<T>(url, options?)` | 发送 DELETE 请求并直接返回 JSON 数据 |
|
|
59
|
+
|
|
60
|
+
### HttpClient 类
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { HttpClient, createHttpClient } from '@lytjs/common-http';
|
|
64
|
+
|
|
65
|
+
const client = new HttpClient({
|
|
66
|
+
baseURL: 'https://api.example.com',
|
|
67
|
+
headers: { 'X-API-Key': 'your-key' },
|
|
68
|
+
timeout: 10000,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// 或者使用工厂函数
|
|
72
|
+
const client = createHttpClient({
|
|
73
|
+
baseURL: 'https://api.example.com',
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 请求选项
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
interface RequestOptions {
|
|
81
|
+
headers?: Record<string, string>;
|
|
82
|
+
params?: Record<string, string | number | boolean | Array<string | number | boolean>>;
|
|
83
|
+
timeout?: number;
|
|
84
|
+
signal?: AbortSignal;
|
|
85
|
+
responseType?: 'json' | 'text' | 'blob' | 'arraybuffer';
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 响应格式
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
interface HttpResponse<T> {
|
|
93
|
+
data: T;
|
|
94
|
+
status: number;
|
|
95
|
+
statusText: string;
|
|
96
|
+
headers: Record<string, string>;
|
|
97
|
+
ok: boolean;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## 特性
|
|
102
|
+
|
|
103
|
+
### 1. 数组查询参数支持
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { get } from '@lytjs/common-http';
|
|
107
|
+
|
|
108
|
+
// 数组参数会被正确地处理为多个相同键名的查询参数
|
|
109
|
+
await get('/api/users', {
|
|
110
|
+
params: {
|
|
111
|
+
ids: [1, 2, 3],
|
|
112
|
+
tags: ['admin', 'user'],
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
// 结果: /api/users?ids=1&ids=2&ids=3&tags=admin&tags=user
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 2. 拦截器
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { http } from '@lytjs/common-http';
|
|
122
|
+
|
|
123
|
+
// 添加请求拦截器
|
|
124
|
+
http.use({
|
|
125
|
+
request(config) {
|
|
126
|
+
config.headers['X-Request-ID'] = Math.random().toString(36);
|
|
127
|
+
return config;
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// 添加响应拦截器
|
|
132
|
+
http.use({
|
|
133
|
+
response(response) {
|
|
134
|
+
console.log('请求成功:', response.status);
|
|
135
|
+
return response;
|
|
136
|
+
},
|
|
137
|
+
error(error) {
|
|
138
|
+
console.error('请求失败:', error);
|
|
139
|
+
throw error;
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 3. 请求取消
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { http } from '@lytjs/common-http';
|
|
148
|
+
|
|
149
|
+
const controller = new AbortController();
|
|
150
|
+
|
|
151
|
+
// 5 秒后取消请求
|
|
152
|
+
setTimeout(() => controller.abort(), 5000);
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
await http.get('/api/slow-endpoint', {
|
|
156
|
+
signal: controller.signal,
|
|
157
|
+
});
|
|
158
|
+
} catch (err) {
|
|
159
|
+
if (err.name === 'AbortError') {
|
|
160
|
+
console.log('请求已取消');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 4. 超时控制
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
import { http, createHttpClient } from '@lytjs/common-http';
|
|
169
|
+
|
|
170
|
+
// 单次请求超时
|
|
171
|
+
await http.get('/api/slow', { timeout: 3000 });
|
|
172
|
+
|
|
173
|
+
// 全局超时配置
|
|
174
|
+
const client = createHttpClient({ timeout: 5000 });
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## 错误处理
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { http, HttpError } from '@lytjs/common-http';
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
const response = await http.get('/api/users');
|
|
184
|
+
} catch (err) {
|
|
185
|
+
if (err instanceof HttpError) {
|
|
186
|
+
console.error('HTTP 错误:', err.status, err.message);
|
|
187
|
+
if (err.response) {
|
|
188
|
+
console.error('响应数据:', err.response.data);
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
console.error('其他错误:', err);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## 完整示例
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { createHttpClient, getJson, postJson, HttpError } from '@lytjs/common-http';
|
|
200
|
+
|
|
201
|
+
// 创建 API 客户端
|
|
202
|
+
const api = createHttpClient({
|
|
203
|
+
baseURL: 'https://api.example.com',
|
|
204
|
+
headers: {
|
|
205
|
+
'Content-Type': 'application/json',
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// 添加身份验证拦截器
|
|
210
|
+
api.use({
|
|
211
|
+
request(config) {
|
|
212
|
+
const token = localStorage.getItem('token');
|
|
213
|
+
if (token) {
|
|
214
|
+
config.headers['Authorization'] = `Bearer ${token}`;
|
|
215
|
+
}
|
|
216
|
+
return config;
|
|
217
|
+
},
|
|
218
|
+
error(err) {
|
|
219
|
+
if (err instanceof HttpError && err.status === 401) {
|
|
220
|
+
// 处理未授权
|
|
221
|
+
window.location.href = '/login';
|
|
222
|
+
}
|
|
223
|
+
throw err;
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// 使用 API 客户端
|
|
228
|
+
async function fetchUsers() {
|
|
229
|
+
try {
|
|
230
|
+
const users = await api.get('/users', {
|
|
231
|
+
params: {
|
|
232
|
+
status: 'active',
|
|
233
|
+
page: 1,
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
return users.data;
|
|
237
|
+
} catch (err) {
|
|
238
|
+
console.error('获取用户失败', err);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// 使用便捷方法
|
|
243
|
+
async function createUser(data: any) {
|
|
244
|
+
try {
|
|
245
|
+
const user = await postJson('/users', data, {
|
|
246
|
+
baseURL: 'https://api.example.com',
|
|
247
|
+
});
|
|
248
|
+
return user;
|
|
249
|
+
} catch (err) {
|
|
250
|
+
console.error('创建用户失败', err);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## License
|
|
256
|
+
|
|
257
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var commonQuery = require('@lytjs/common-query');
|
|
4
|
+
|
|
3
5
|
// src/index.ts
|
|
4
6
|
var HttpError = class extends Error {
|
|
5
7
|
constructor(message, response) {
|
|
@@ -70,14 +72,18 @@ var HttpClient = class {
|
|
|
70
72
|
let httpResponse = await this._parseResponse(response, config.responseType);
|
|
71
73
|
for (const interceptor of this._interceptors) {
|
|
72
74
|
if (interceptor.response) {
|
|
73
|
-
httpResponse = await interceptor.response(
|
|
75
|
+
httpResponse = await interceptor.response(
|
|
76
|
+
httpResponse
|
|
77
|
+
);
|
|
74
78
|
}
|
|
75
79
|
}
|
|
76
80
|
return httpResponse;
|
|
77
81
|
} catch (err) {
|
|
78
82
|
for (const interceptor of this._interceptors) {
|
|
79
83
|
if (interceptor.error) {
|
|
80
|
-
const result = interceptor.error(
|
|
84
|
+
const result = interceptor.error(
|
|
85
|
+
err instanceof HttpError ? err : new HttpError(String(err))
|
|
86
|
+
);
|
|
81
87
|
if (result !== void 0) return result;
|
|
82
88
|
}
|
|
83
89
|
}
|
|
@@ -124,8 +130,7 @@ var HttpClient = class {
|
|
|
124
130
|
_resolveURL(base, url, params) {
|
|
125
131
|
let resolved = base ? base.replace(/\/+$/, "") + "/" + url.replace(/^\/+/, "") : url;
|
|
126
132
|
if (params) {
|
|
127
|
-
const
|
|
128
|
-
const qs = searchParams.toString();
|
|
133
|
+
const qs = commonQuery.stringifyQueryString(params);
|
|
129
134
|
if (qs) {
|
|
130
135
|
resolved += (resolved.includes("?") ? "&" : "?") + qs;
|
|
131
136
|
}
|
|
@@ -144,10 +149,14 @@ var HttpClient = class {
|
|
|
144
149
|
clearTimeout(timeoutId);
|
|
145
150
|
throw new HttpError("Request was aborted", void 0);
|
|
146
151
|
}
|
|
147
|
-
signal.addEventListener(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
152
|
+
signal.addEventListener(
|
|
153
|
+
"abort",
|
|
154
|
+
() => {
|
|
155
|
+
clearTimeout(timeoutId);
|
|
156
|
+
timeoutController.abort();
|
|
157
|
+
},
|
|
158
|
+
{ once: true }
|
|
159
|
+
);
|
|
151
160
|
}
|
|
152
161
|
}
|
|
153
162
|
const fetchOptions = {
|
|
@@ -167,10 +176,7 @@ var HttpClient = class {
|
|
|
167
176
|
headers: this._parseHeaders(response.headers),
|
|
168
177
|
ok: false
|
|
169
178
|
};
|
|
170
|
-
throw new HttpError(
|
|
171
|
-
`HTTP ${response.status}: ${response.statusText}`,
|
|
172
|
-
errorResponse
|
|
173
|
-
);
|
|
179
|
+
throw new HttpError(`HTTP ${response.status}: ${response.statusText}`, errorResponse);
|
|
174
180
|
}
|
|
175
181
|
return response;
|
|
176
182
|
} finally {
|
|
@@ -218,11 +224,61 @@ function createHttpClient(options) {
|
|
|
218
224
|
return new HttpClient(options);
|
|
219
225
|
}
|
|
220
226
|
var http = new HttpClient();
|
|
227
|
+
function get(url, options) {
|
|
228
|
+
return http.get(url, options);
|
|
229
|
+
}
|
|
230
|
+
function post(url, data, options) {
|
|
231
|
+
return http.post(url, data, options);
|
|
232
|
+
}
|
|
233
|
+
function put(url, data, options) {
|
|
234
|
+
return http.put(url, data, options);
|
|
235
|
+
}
|
|
236
|
+
function del(url, options) {
|
|
237
|
+
return http.delete(url, options);
|
|
238
|
+
}
|
|
239
|
+
function patch(url, data, options) {
|
|
240
|
+
return http.patch(url, data, options);
|
|
241
|
+
}
|
|
242
|
+
async function requestJson(method, url, options) {
|
|
243
|
+
const { data, ...config } = options || {};
|
|
244
|
+
if (method === "GET" || method === "DELETE") {
|
|
245
|
+
const response2 = await http.request(method, url, config);
|
|
246
|
+
return response2.data;
|
|
247
|
+
}
|
|
248
|
+
const response = await http.request(method, url, { ...config, body: data });
|
|
249
|
+
return response.data;
|
|
250
|
+
}
|
|
251
|
+
async function getJson(url, options) {
|
|
252
|
+
return requestJson("GET", url, options);
|
|
253
|
+
}
|
|
254
|
+
async function postJson(url, data, options) {
|
|
255
|
+
return requestJson("POST", url, { ...options, data });
|
|
256
|
+
}
|
|
257
|
+
async function putJson(url, data, options) {
|
|
258
|
+
return requestJson("PUT", url, { ...options, data });
|
|
259
|
+
}
|
|
260
|
+
async function patchJson(url, data, options) {
|
|
261
|
+
return requestJson("PATCH", url, { ...options, data });
|
|
262
|
+
}
|
|
263
|
+
async function deleteJson(url, options) {
|
|
264
|
+
return requestJson("DELETE", url, options);
|
|
265
|
+
}
|
|
221
266
|
|
|
222
267
|
exports.CancellationToken = CancellationToken;
|
|
223
268
|
exports.HttpClient = HttpClient;
|
|
224
269
|
exports.HttpError = HttpError;
|
|
225
270
|
exports.createHttpClient = createHttpClient;
|
|
271
|
+
exports.del = del;
|
|
272
|
+
exports.deleteJson = deleteJson;
|
|
273
|
+
exports.get = get;
|
|
274
|
+
exports.getJson = getJson;
|
|
226
275
|
exports.http = http;
|
|
276
|
+
exports.patch = patch;
|
|
277
|
+
exports.patchJson = patchJson;
|
|
278
|
+
exports.post = post;
|
|
279
|
+
exports.postJson = postJson;
|
|
280
|
+
exports.put = put;
|
|
281
|
+
exports.putJson = putJson;
|
|
282
|
+
exports.requestJson = requestJson;
|
|
227
283
|
//# sourceMappingURL=index.cjs.map
|
|
228
284
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * @lytjs/common-http\r\n * Lightweight HTTP client based on native fetch API\r\n */\r\n\r\n// --- Types ---\r\n\r\nexport interface HttpClientOptions {\r\n baseURL?: string;\r\n headers?: Record<string, string>;\r\n timeout?: number;\r\n withCredentials?: boolean;\r\n}\r\n\r\nexport interface RequestOptions {\r\n headers?: Record<string, string>;\r\n params?: Record<string, string>;\r\n timeout?: number;\r\n signal?: AbortSignal;\r\n responseType?: 'json' | 'text' | 'blob' | 'arraybuffer';\r\n}\r\n\r\nexport interface HttpResponse<T> {\r\n data: T;\r\n status: number;\r\n statusText: string;\r\n headers: Record<string, string>;\r\n ok: boolean;\r\n}\r\n\r\nexport interface InternalRequestConfig {\r\n method: string;\r\n url: string;\r\n headers: Record<string, string>;\r\n body?: BodyInit | null;\r\n signal?: AbortSignal;\r\n responseType?: 'json' | 'text' | 'blob' | 'arraybuffer';\r\n withCredentials?: boolean;\r\n timeout?: number;\r\n}\r\n\r\nexport interface Interceptor {\r\n request?(config: InternalRequestConfig): InternalRequestConfig | Promise<InternalRequestConfig>;\r\n response?(response: HttpResponse<unknown>): HttpResponse<unknown> | Promise<HttpResponse<unknown>>;\r\n error?(error: HttpError): unknown;\r\n}\r\n\r\n// --- HttpError ---\r\n\r\nexport class HttpError extends Error {\r\n readonly response?: HttpResponse<unknown>;\r\n readonly status?: number;\r\n\r\n constructor(message: string, response?: HttpResponse<unknown>) {\r\n super(message);\r\n this.name = 'HttpError';\r\n this.response = response;\r\n this.status = response?.status;\r\n }\r\n}\r\n\r\n// --- CancellationToken ---\r\n\r\nexport class CancellationToken {\r\n private readonly _controller: AbortController;\r\n private readonly _linkedTokens: CancellationToken[];\r\n\r\n constructor() {\r\n this._controller = new AbortController();\r\n this._linkedTokens = [];\r\n }\r\n\r\n get signal(): AbortSignal {\r\n return this._controller.signal;\r\n }\r\n\r\n cancel(): void {\r\n this._controller.abort();\r\n for (const token of this._linkedTokens) {\r\n token.cancel();\r\n }\r\n }\r\n\r\n get isCancelled(): boolean {\r\n return this._controller.signal.aborted;\r\n }\r\n\r\n static createLinkedToken(...tokens: CancellationToken[]): CancellationToken {\r\n const linked = new CancellationToken();\r\n for (const token of tokens) {\r\n token._linkedTokens.push(linked);\r\n if (token.isCancelled) {\r\n linked.cancel();\r\n return linked;\r\n }\r\n }\r\n return linked;\r\n }\r\n}\r\n\r\n// --- HttpClient ---\r\n\r\nexport class HttpClient {\r\n private readonly _options: HttpClientOptions;\r\n private readonly _interceptors: Interceptor[];\r\n\r\n constructor(options?: HttpClientOptions) {\r\n this._options = { ...options };\r\n this._interceptors = [];\r\n }\r\n\r\n get<T = unknown>(url: string, options?: RequestOptions): Promise<HttpResponse<T>> {\r\n return this.request<T>('GET', url, options);\r\n }\r\n\r\n post<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<HttpResponse<T>> {\r\n return this.request<T>('POST', url, { ...options, body: data } as RequestOptions & { body?: unknown });\r\n }\r\n\r\n put<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<HttpResponse<T>> {\r\n return this.request<T>('PUT', url, { ...options, body: data } as RequestOptions & { body?: unknown });\r\n }\r\n\r\n delete<T = unknown>(url: string, options?: RequestOptions): Promise<HttpResponse<T>> {\r\n return this.request<T>('DELETE', url, options);\r\n }\r\n\r\n patch<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<HttpResponse<T>> {\r\n return this.request<T>('PATCH', url, { ...options, body: data } as RequestOptions & { body?: unknown });\r\n }\r\n\r\n async request<T = unknown>(\r\n method: string,\r\n url: string,\r\n options?: RequestOptions & { body?: unknown },\r\n ): Promise<HttpResponse<T>> {\r\n let config = this._buildConfig(method, url, options);\r\n\r\n // Apply request interceptors\r\n for (const interceptor of this._interceptors) {\r\n if (interceptor.request) {\r\n config = await interceptor.request(config);\r\n }\r\n }\r\n\r\n try {\r\n const response = await this._fetch(config);\r\n let httpResponse = await this._parseResponse<T>(response, config.responseType);\r\n\r\n // Apply response interceptors\r\n for (const interceptor of this._interceptors) {\r\n if (interceptor.response) {\r\n httpResponse = (await interceptor.response(httpResponse as HttpResponse<unknown>)) as HttpResponse<T>;\r\n }\r\n }\r\n\r\n return httpResponse;\r\n } catch (err) {\r\n // Apply error interceptors\r\n for (const interceptor of this._interceptors) {\r\n if (interceptor.error) {\r\n const result = interceptor.error(err instanceof HttpError ? err : new HttpError(String(err)));\r\n if (result !== undefined) return result as HttpResponse<T>;\r\n }\r\n }\r\n throw err;\r\n }\r\n }\r\n\r\n use(interceptor: Interceptor): () => void {\r\n this._interceptors.push(interceptor);\r\n return () => this.eject(interceptor);\r\n }\r\n\r\n eject(interceptor: Interceptor): void {\r\n const index = this._interceptors.indexOf(interceptor);\r\n if (index !== -1) {\r\n this._interceptors.splice(index, 1);\r\n }\r\n }\r\n\r\n private _buildConfig(\r\n method: string,\r\n url: string,\r\n options?: RequestOptions & { body?: unknown },\r\n ): InternalRequestConfig {\r\n const { baseURL = '', headers: defaultHeaders = {} } = this._options;\r\n const resolvedURL = this._resolveURL(baseURL, url, options?.params);\r\n\r\n const headers: Record<string, string> = { ...defaultHeaders, ...options?.headers };\r\n\r\n let body: BodyInit | null = null;\r\n if (options && 'body' in options && options.body !== undefined) {\r\n if (typeof options.body === 'object' && options.body !== null) {\r\n body = JSON.stringify(options.body);\r\n if (!headers['Content-Type']) {\r\n headers['Content-Type'] = 'application/json';\r\n }\r\n } else {\r\n body = String(options.body);\r\n }\r\n }\r\n\r\n const timeout = options?.timeout ?? this._options.timeout;\r\n\r\n return {\r\n method: method.toUpperCase(),\r\n url: resolvedURL,\r\n headers,\r\n body,\r\n signal: options?.signal,\r\n responseType: options?.responseType,\r\n withCredentials: this._options.withCredentials,\r\n timeout,\r\n };\r\n }\r\n\r\n private _resolveURL(base: string, url: string, params?: Record<string, string>): string {\r\n let resolved = base ? base.replace(/\\/+$/, '') + '/' + url.replace(/^\\/+/, '') : url;\r\n if (params) {\r\n const searchParams = new URLSearchParams(params);\r\n const qs = searchParams.toString();\r\n if (qs) {\r\n resolved += (resolved.includes('?') ? '&' : '?') + qs;\r\n }\r\n }\r\n return resolved;\r\n }\r\n\r\n private async _fetch(config: InternalRequestConfig): Promise<Response> {\r\n const { method, url, headers, body, signal, withCredentials, timeout } = config;\r\n\r\n // Handle timeout via AbortController\r\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\r\n let timeoutController: AbortController | undefined;\r\n\r\n if (timeout && timeout > 0) {\r\n timeoutController = new AbortController();\r\n timeoutId = setTimeout(() => timeoutController!.abort(), timeout);\r\n\r\n // Link with existing signal\r\n if (signal) {\r\n if (signal.aborted) {\r\n clearTimeout(timeoutId);\r\n throw new HttpError('Request was aborted', undefined);\r\n }\r\n signal.addEventListener('abort', () => {\r\n clearTimeout(timeoutId);\r\n timeoutController!.abort();\r\n }, { once: true });\r\n }\r\n }\r\n\r\n const fetchOptions: RequestInit = {\r\n method,\r\n headers,\r\n body,\r\n credentials: withCredentials ? 'include' : undefined,\r\n signal: timeoutController ? timeoutController.signal : signal,\r\n };\r\n\r\n try {\r\n const response = await fetch(url, fetchOptions);\r\n\r\n if (!response.ok) {\r\n const errorResponse: HttpResponse<unknown> = {\r\n data: null,\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers: this._parseHeaders(response.headers),\r\n ok: false,\r\n };\r\n throw new HttpError(\r\n `HTTP ${response.status}: ${response.statusText}`,\r\n errorResponse,\r\n );\r\n }\r\n\r\n return response;\r\n } finally {\r\n if (timeoutId !== undefined) {\r\n clearTimeout(timeoutId);\r\n }\r\n }\r\n }\r\n\r\n private async _parseResponse<T>(\r\n response: Response,\r\n responseType?: 'json' | 'text' | 'blob' | 'arraybuffer',\r\n ): Promise<HttpResponse<T>> {\r\n let data: T;\r\n switch (responseType) {\r\n case 'text':\r\n data = (await response.text()) as unknown as T;\r\n break;\r\n case 'blob':\r\n data = (await response.blob()) as unknown as T;\r\n break;\r\n case 'arraybuffer':\r\n data = (await response.arrayBuffer()) as unknown as T;\r\n break;\r\n case 'json':\r\n default: {\r\n const text = await response.text();\r\n data = text ? JSON.parse(text) : (null as unknown as T);\r\n break;\r\n }\r\n }\r\n\r\n return {\r\n data,\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers: this._parseHeaders(response.headers),\r\n ok: response.ok,\r\n };\r\n }\r\n\r\n private _parseHeaders(headers: Headers): Record<string, string> {\r\n const result: Record<string, string> = {};\r\n headers.forEach((value, key) => {\r\n result[key] = value;\r\n });\r\n return result;\r\n }\r\n}\r\n\r\n// --- Convenience exports ---\r\n\r\nexport function createHttpClient(options?: HttpClientOptions): HttpClient {\r\n return new HttpClient(options);\r\n}\r\n\r\nexport const http: HttpClient = new HttpClient();\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["stringifyQueryString","response"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @lytjs/common-http\n * Lightweight HTTP client based on native fetch API\n */\n\n// --- Imports ---\nimport { stringifyQueryString } from '@lytjs/common-query';\n\n// --- Types ---\n\nexport interface HttpClientOptions {\n baseURL?: string;\n headers?: Record<string, string>;\n timeout?: number;\n withCredentials?: boolean;\n}\n\nexport interface RequestOptions {\n headers?: Record<string, string>;\n params?: Record<string, string | number | boolean | Array<string | number | boolean>>;\n timeout?: number;\n signal?: AbortSignal;\n responseType?: 'json' | 'text' | 'blob' | 'arraybuffer';\n}\n\nexport interface HttpResponse<T> {\n data: T;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n ok: boolean;\n}\n\nexport interface InternalRequestConfig {\n method: string;\n url: string;\n headers: Record<string, string>;\n body?: BodyInit | null;\n signal?: AbortSignal;\n responseType?: 'json' | 'text' | 'blob' | 'arraybuffer';\n withCredentials?: boolean;\n timeout?: number;\n}\n\nexport interface Interceptor {\n request?(config: InternalRequestConfig): InternalRequestConfig | Promise<InternalRequestConfig>;\n response?(\n response: HttpResponse<unknown>,\n ): HttpResponse<unknown> | Promise<HttpResponse<unknown>>;\n error?(error: HttpError): unknown;\n}\n\n// --- HttpError ---\n\nexport class HttpError extends Error {\n readonly response?: HttpResponse<unknown>;\n readonly status?: number;\n\n constructor(message: string, response?: HttpResponse<unknown>) {\n super(message);\n this.name = 'HttpError';\n this.response = response;\n this.status = response?.status;\n }\n}\n\n// --- CancellationToken ---\n\nexport class CancellationToken {\n private readonly _controller: AbortController;\n private readonly _linkedTokens: CancellationToken[];\n\n constructor() {\n this._controller = new AbortController();\n this._linkedTokens = [];\n }\n\n get signal(): AbortSignal {\n return this._controller.signal;\n }\n\n cancel(): void {\n this._controller.abort();\n for (const token of this._linkedTokens) {\n token.cancel();\n }\n }\n\n get isCancelled(): boolean {\n return this._controller.signal.aborted;\n }\n\n static createLinkedToken(...tokens: CancellationToken[]): CancellationToken {\n const linked = new CancellationToken();\n for (const token of tokens) {\n token._linkedTokens.push(linked);\n if (token.isCancelled) {\n linked.cancel();\n return linked;\n }\n }\n return linked;\n }\n}\n\n// --- HttpClient ---\n\nexport class HttpClient {\n private readonly _options: HttpClientOptions;\n private readonly _interceptors: Interceptor[];\n\n constructor(options?: HttpClientOptions) {\n this._options = { ...options };\n this._interceptors = [];\n }\n\n get<T = unknown>(url: string, options?: RequestOptions): Promise<HttpResponse<T>> {\n return this.request<T>('GET', url, options);\n }\n\n post<T = unknown>(\n url: string,\n data?: unknown,\n options?: RequestOptions,\n ): Promise<HttpResponse<T>> {\n return this.request<T>('POST', url, { ...options, body: data } as RequestOptions & {\n body?: unknown;\n });\n }\n\n put<T = unknown>(\n url: string,\n data?: unknown,\n options?: RequestOptions,\n ): Promise<HttpResponse<T>> {\n return this.request<T>('PUT', url, { ...options, body: data } as RequestOptions & {\n body?: unknown;\n });\n }\n\n delete<T = unknown>(url: string, options?: RequestOptions): Promise<HttpResponse<T>> {\n return this.request<T>('DELETE', url, options);\n }\n\n patch<T = unknown>(\n url: string,\n data?: unknown,\n options?: RequestOptions,\n ): Promise<HttpResponse<T>> {\n return this.request<T>('PATCH', url, { ...options, body: data } as RequestOptions & {\n body?: unknown;\n });\n }\n\n async request<T = unknown>(\n method: string,\n url: string,\n options?: RequestOptions & { body?: unknown },\n ): Promise<HttpResponse<T>> {\n let config = this._buildConfig(method, url, options);\n\n // Apply request interceptors\n for (const interceptor of this._interceptors) {\n if (interceptor.request) {\n config = await interceptor.request(config);\n }\n }\n\n try {\n const response = await this._fetch(config);\n let httpResponse = await this._parseResponse<T>(response, config.responseType);\n\n // Apply response interceptors\n for (const interceptor of this._interceptors) {\n if (interceptor.response) {\n httpResponse = (await interceptor.response(\n httpResponse as HttpResponse<unknown>,\n )) as HttpResponse<T>;\n }\n }\n\n return httpResponse;\n } catch (err) {\n // Apply error interceptors\n for (const interceptor of this._interceptors) {\n if (interceptor.error) {\n const result = interceptor.error(\n err instanceof HttpError ? err : new HttpError(String(err)),\n );\n if (result !== undefined) return result as HttpResponse<T>;\n }\n }\n throw err;\n }\n }\n\n use(interceptor: Interceptor): () => void {\n this._interceptors.push(interceptor);\n return () => this.eject(interceptor);\n }\n\n eject(interceptor: Interceptor): void {\n const index = this._interceptors.indexOf(interceptor);\n if (index !== -1) {\n this._interceptors.splice(index, 1);\n }\n }\n\n private _buildConfig(\n method: string,\n url: string,\n options?: RequestOptions & { body?: unknown },\n ): InternalRequestConfig {\n const { baseURL = '', headers: defaultHeaders = {} } = this._options;\n const resolvedURL = this._resolveURL(baseURL, url, options?.params);\n\n const headers: Record<string, string> = { ...defaultHeaders, ...options?.headers };\n\n let body: BodyInit | null = null;\n if (options && 'body' in options && options.body !== undefined) {\n if (typeof options.body === 'object' && options.body !== null) {\n body = JSON.stringify(options.body);\n if (!headers['Content-Type']) {\n headers['Content-Type'] = 'application/json';\n }\n } else {\n body = String(options.body);\n }\n }\n\n const timeout = options?.timeout ?? this._options.timeout;\n\n return {\n method: method.toUpperCase(),\n url: resolvedURL,\n headers,\n body,\n signal: options?.signal,\n responseType: options?.responseType,\n withCredentials: this._options.withCredentials,\n timeout,\n };\n }\n\n private _resolveURL(\n base: string,\n url: string,\n params?: Record<string, string | number | boolean | Array<string | number | boolean>>,\n ): string {\n let resolved = base ? base.replace(/\\/+$/, '') + '/' + url.replace(/^\\/+/, '') : url;\n if (params) {\n const qs = stringifyQueryString(params);\n if (qs) {\n resolved += (resolved.includes('?') ? '&' : '?') + qs;\n }\n }\n return resolved;\n }\n\n private async _fetch(config: InternalRequestConfig): Promise<Response> {\n const { method, url, headers, body, signal, withCredentials, timeout } = config;\n\n // Handle timeout via AbortController\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let timeoutController: AbortController | undefined;\n\n if (timeout && timeout > 0) {\n timeoutController = new AbortController();\n timeoutId = setTimeout(() => timeoutController!.abort(), timeout);\n\n // Link with existing signal\n if (signal) {\n if (signal.aborted) {\n clearTimeout(timeoutId);\n throw new HttpError('Request was aborted', undefined);\n }\n signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timeoutId);\n timeoutController!.abort();\n },\n { once: true },\n );\n }\n }\n\n const fetchOptions: RequestInit = {\n method,\n headers,\n body,\n credentials: withCredentials ? 'include' : undefined,\n signal: timeoutController ? timeoutController.signal : signal,\n };\n\n try {\n const response = await fetch(url, fetchOptions);\n\n if (!response.ok) {\n const errorResponse: HttpResponse<unknown> = {\n data: null,\n status: response.status,\n statusText: response.statusText,\n headers: this._parseHeaders(response.headers),\n ok: false,\n };\n throw new HttpError(`HTTP ${response.status}: ${response.statusText}`, errorResponse);\n }\n\n return response;\n } finally {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n private async _parseResponse<T>(\n response: Response,\n responseType?: 'json' | 'text' | 'blob' | 'arraybuffer',\n ): Promise<HttpResponse<T>> {\n let data: T;\n switch (responseType) {\n case 'text':\n data = (await response.text()) as unknown as T;\n break;\n case 'blob':\n data = (await response.blob()) as unknown as T;\n break;\n case 'arraybuffer':\n data = (await response.arrayBuffer()) as unknown as T;\n break;\n case 'json':\n default: {\n const text = await response.text();\n data = text ? JSON.parse(text) : (null as unknown as T);\n break;\n }\n }\n\n return {\n data,\n status: response.status,\n statusText: response.statusText,\n headers: this._parseHeaders(response.headers),\n ok: response.ok,\n };\n }\n\n private _parseHeaders(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n }\n}\n\n// --- Convenience exports ---\n\nexport function createHttpClient(options?: HttpClientOptions): HttpClient {\n return new HttpClient(options);\n}\n\nexport const http: HttpClient = new HttpClient();\n\n// --- Convenience methods for the default http client ---\n\n/**\n * 便捷 GET 请求\n */\nexport function get<T = unknown>(url: string, options?: RequestOptions): Promise<HttpResponse<T>> {\n return http.get<T>(url, options);\n}\n\n/**\n * 便捷 POST 请求\n */\nexport function post<T = unknown>(\n url: string,\n data?: unknown,\n options?: RequestOptions,\n): Promise<HttpResponse<T>> {\n return http.post<T>(url, data, options);\n}\n\n/**\n * 便捷 PUT 请求\n */\nexport function put<T = unknown>(\n url: string,\n data?: unknown,\n options?: RequestOptions,\n): Promise<HttpResponse<T>> {\n return http.put<T>(url, data, options);\n}\n\n/**\n * 便捷 DELETE 请求\n */\nexport function del<T = unknown>(url: string, options?: RequestOptions): Promise<HttpResponse<T>> {\n return http.delete<T>(url, options);\n}\n\n/**\n * 便捷 PATCH 请求\n */\nexport function patch<T = unknown>(\n url: string,\n data?: unknown,\n options?: RequestOptions,\n): Promise<HttpResponse<T>> {\n return http.patch<T>(url, data, options);\n}\n\n/**\n * 发送 JSON 请求并直接获取数据\n * 自动处理响应解析和错误\n */\nexport async function requestJson<T = unknown>(\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',\n url: string,\n options?: RequestOptions & { data?: unknown },\n): Promise<T> {\n const { data, ...config } = options || {};\n\n if (method === 'GET' || method === 'DELETE') {\n const response = await http.request<T>(method, url, config);\n return response.data;\n }\n\n const response = await http.request<T>(method, url, { ...config, body: data });\n return response.data;\n}\n\n/**\n * 发送 GET JSON 请求\n */\nexport async function getJson<T = unknown>(url: string, options?: RequestOptions): Promise<T> {\n return requestJson<T>('GET', url, options);\n}\n\n/**\n * 发送 POST JSON 请求\n */\nexport async function postJson<T = unknown>(\n url: string,\n data?: unknown,\n options?: RequestOptions,\n): Promise<T> {\n return requestJson<T>('POST', url, { ...options, data });\n}\n\n/**\n * 发送 PUT JSON 请求\n */\nexport async function putJson<T = unknown>(\n url: string,\n data?: unknown,\n options?: RequestOptions,\n): Promise<T> {\n return requestJson<T>('PUT', url, { ...options, data });\n}\n\n/**\n * 发送 PATCH JSON 请求\n */\nexport async function patchJson<T = unknown>(\n url: string,\n data?: unknown,\n options?: RequestOptions,\n): Promise<T> {\n return requestJson<T>('PATCH', url, { ...options, data });\n}\n\n/**\n * 发送 DELETE JSON 请求\n */\nexport async function deleteJson<T = unknown>(url: string, options?: RequestOptions): Promise<T> {\n return requestJson<T>('DELETE', url, options);\n}\n"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -10,7 +10,7 @@ interface HttpClientOptions {
|
|
|
10
10
|
}
|
|
11
11
|
interface RequestOptions {
|
|
12
12
|
headers?: Record<string, string>;
|
|
13
|
-
params?: Record<string, string
|
|
13
|
+
params?: Record<string, string | number | boolean | Array<string | number | boolean>>;
|
|
14
14
|
timeout?: number;
|
|
15
15
|
signal?: AbortSignal;
|
|
16
16
|
responseType?: 'json' | 'text' | 'blob' | 'arraybuffer';
|
|
@@ -73,5 +73,52 @@ declare class HttpClient {
|
|
|
73
73
|
}
|
|
74
74
|
declare function createHttpClient(options?: HttpClientOptions): HttpClient;
|
|
75
75
|
declare const http: HttpClient;
|
|
76
|
+
/**
|
|
77
|
+
* 便捷 GET 请求
|
|
78
|
+
*/
|
|
79
|
+
declare function get<T = unknown>(url: string, options?: RequestOptions): Promise<HttpResponse<T>>;
|
|
80
|
+
/**
|
|
81
|
+
* 便捷 POST 请求
|
|
82
|
+
*/
|
|
83
|
+
declare function post<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<HttpResponse<T>>;
|
|
84
|
+
/**
|
|
85
|
+
* 便捷 PUT 请求
|
|
86
|
+
*/
|
|
87
|
+
declare function put<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<HttpResponse<T>>;
|
|
88
|
+
/**
|
|
89
|
+
* 便捷 DELETE 请求
|
|
90
|
+
*/
|
|
91
|
+
declare function del<T = unknown>(url: string, options?: RequestOptions): Promise<HttpResponse<T>>;
|
|
92
|
+
/**
|
|
93
|
+
* 便捷 PATCH 请求
|
|
94
|
+
*/
|
|
95
|
+
declare function patch<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<HttpResponse<T>>;
|
|
96
|
+
/**
|
|
97
|
+
* 发送 JSON 请求并直接获取数据
|
|
98
|
+
* 自动处理响应解析和错误
|
|
99
|
+
*/
|
|
100
|
+
declare function requestJson<T = unknown>(method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE', url: string, options?: RequestOptions & {
|
|
101
|
+
data?: unknown;
|
|
102
|
+
}): Promise<T>;
|
|
103
|
+
/**
|
|
104
|
+
* 发送 GET JSON 请求
|
|
105
|
+
*/
|
|
106
|
+
declare function getJson<T = unknown>(url: string, options?: RequestOptions): Promise<T>;
|
|
107
|
+
/**
|
|
108
|
+
* 发送 POST JSON 请求
|
|
109
|
+
*/
|
|
110
|
+
declare function postJson<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<T>;
|
|
111
|
+
/**
|
|
112
|
+
* 发送 PUT JSON 请求
|
|
113
|
+
*/
|
|
114
|
+
declare function putJson<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<T>;
|
|
115
|
+
/**
|
|
116
|
+
* 发送 PATCH JSON 请求
|
|
117
|
+
*/
|
|
118
|
+
declare function patchJson<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<T>;
|
|
119
|
+
/**
|
|
120
|
+
* 发送 DELETE JSON 请求
|
|
121
|
+
*/
|
|
122
|
+
declare function deleteJson<T = unknown>(url: string, options?: RequestOptions): Promise<T>;
|
|
76
123
|
|
|
77
|
-
export { CancellationToken, HttpClient, type HttpClientOptions, HttpError, type HttpResponse, type Interceptor, type InternalRequestConfig, type RequestOptions, createHttpClient, http };
|
|
124
|
+
export { CancellationToken, HttpClient, type HttpClientOptions, HttpError, type HttpResponse, type Interceptor, type InternalRequestConfig, type RequestOptions, createHttpClient, del, deleteJson, get, getJson, http, patch, patchJson, post, postJson, put, putJson, requestJson };
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ interface HttpClientOptions {
|
|
|
10
10
|
}
|
|
11
11
|
interface RequestOptions {
|
|
12
12
|
headers?: Record<string, string>;
|
|
13
|
-
params?: Record<string, string
|
|
13
|
+
params?: Record<string, string | number | boolean | Array<string | number | boolean>>;
|
|
14
14
|
timeout?: number;
|
|
15
15
|
signal?: AbortSignal;
|
|
16
16
|
responseType?: 'json' | 'text' | 'blob' | 'arraybuffer';
|
|
@@ -73,5 +73,52 @@ declare class HttpClient {
|
|
|
73
73
|
}
|
|
74
74
|
declare function createHttpClient(options?: HttpClientOptions): HttpClient;
|
|
75
75
|
declare const http: HttpClient;
|
|
76
|
+
/**
|
|
77
|
+
* 便捷 GET 请求
|
|
78
|
+
*/
|
|
79
|
+
declare function get<T = unknown>(url: string, options?: RequestOptions): Promise<HttpResponse<T>>;
|
|
80
|
+
/**
|
|
81
|
+
* 便捷 POST 请求
|
|
82
|
+
*/
|
|
83
|
+
declare function post<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<HttpResponse<T>>;
|
|
84
|
+
/**
|
|
85
|
+
* 便捷 PUT 请求
|
|
86
|
+
*/
|
|
87
|
+
declare function put<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<HttpResponse<T>>;
|
|
88
|
+
/**
|
|
89
|
+
* 便捷 DELETE 请求
|
|
90
|
+
*/
|
|
91
|
+
declare function del<T = unknown>(url: string, options?: RequestOptions): Promise<HttpResponse<T>>;
|
|
92
|
+
/**
|
|
93
|
+
* 便捷 PATCH 请求
|
|
94
|
+
*/
|
|
95
|
+
declare function patch<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<HttpResponse<T>>;
|
|
96
|
+
/**
|
|
97
|
+
* 发送 JSON 请求并直接获取数据
|
|
98
|
+
* 自动处理响应解析和错误
|
|
99
|
+
*/
|
|
100
|
+
declare function requestJson<T = unknown>(method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE', url: string, options?: RequestOptions & {
|
|
101
|
+
data?: unknown;
|
|
102
|
+
}): Promise<T>;
|
|
103
|
+
/**
|
|
104
|
+
* 发送 GET JSON 请求
|
|
105
|
+
*/
|
|
106
|
+
declare function getJson<T = unknown>(url: string, options?: RequestOptions): Promise<T>;
|
|
107
|
+
/**
|
|
108
|
+
* 发送 POST JSON 请求
|
|
109
|
+
*/
|
|
110
|
+
declare function postJson<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<T>;
|
|
111
|
+
/**
|
|
112
|
+
* 发送 PUT JSON 请求
|
|
113
|
+
*/
|
|
114
|
+
declare function putJson<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<T>;
|
|
115
|
+
/**
|
|
116
|
+
* 发送 PATCH JSON 请求
|
|
117
|
+
*/
|
|
118
|
+
declare function patchJson<T = unknown>(url: string, data?: unknown, options?: RequestOptions): Promise<T>;
|
|
119
|
+
/**
|
|
120
|
+
* 发送 DELETE JSON 请求
|
|
121
|
+
*/
|
|
122
|
+
declare function deleteJson<T = unknown>(url: string, options?: RequestOptions): Promise<T>;
|
|
76
123
|
|
|
77
|
-
export { CancellationToken, HttpClient, type HttpClientOptions, HttpError, type HttpResponse, type Interceptor, type InternalRequestConfig, type RequestOptions, createHttpClient, http };
|
|
124
|
+
export { CancellationToken, HttpClient, type HttpClientOptions, HttpError, type HttpResponse, type Interceptor, type InternalRequestConfig, type RequestOptions, createHttpClient, del, deleteJson, get, getJson, http, patch, patchJson, post, postJson, put, putJson, requestJson };
|