@be-link/http 1.1.0 → 1.2.1
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/dist/BeLinkHttp.d.ts +115 -19
- package/dist/BeLinkHttp.d.ts.map +1 -1
- package/dist/adapters/AxiosAdapter.d.ts +40 -0
- package/dist/adapters/AxiosAdapter.d.ts.map +1 -0
- package/dist/adapters/TaroAdapter.d.ts +68 -0
- package/dist/adapters/TaroAdapter.d.ts.map +1 -0
- package/dist/adapters/index.d.ts +11 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/types.d.ts +136 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/index.cjs.js +555 -220
- package/dist/index.d.ts +35 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +553 -221
- package/dist/interceptors/core.d.ts +58 -0
- package/dist/interceptors/core.d.ts.map +1 -0
- package/dist/services/TimeSyncService.d.ts +41 -1
- package/dist/services/TimeSyncService.d.ts.map +1 -1
- package/dist/types.d.ts +24 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -5,6 +5,319 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var axios = require('axios');
|
|
6
6
|
var CryptoJS = require('crypto-js');
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Axios 适配器
|
|
10
|
+
*
|
|
11
|
+
* 使用 Axios 实现 HttpAdapter 接口
|
|
12
|
+
*
|
|
13
|
+
* @module adapters/AxiosAdapter
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Axios 适配器
|
|
17
|
+
*
|
|
18
|
+
* 将 Axios 封装为统一的 HttpAdapter 接口
|
|
19
|
+
*/
|
|
20
|
+
class AxiosAdapter {
|
|
21
|
+
/**
|
|
22
|
+
* 创建 Axios 适配器实例
|
|
23
|
+
*
|
|
24
|
+
* @param config - 适配器配置
|
|
25
|
+
*/
|
|
26
|
+
constructor(config) {
|
|
27
|
+
this.instance = axios.create({
|
|
28
|
+
baseURL: config.baseURL,
|
|
29
|
+
timeout: config.timeout || 30000,
|
|
30
|
+
headers: {
|
|
31
|
+
'Content-Type': 'application/json',
|
|
32
|
+
...(config.headers || {}),
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 发起 HTTP 请求
|
|
38
|
+
*
|
|
39
|
+
* @param config - 请求配置
|
|
40
|
+
* @returns Promise 响应数据
|
|
41
|
+
*/
|
|
42
|
+
async request(config) {
|
|
43
|
+
const axiosConfig = {
|
|
44
|
+
url: config.url,
|
|
45
|
+
method: config.method || 'GET',
|
|
46
|
+
data: config.data,
|
|
47
|
+
headers: config.headers,
|
|
48
|
+
timeout: config.timeout,
|
|
49
|
+
params: config.params,
|
|
50
|
+
};
|
|
51
|
+
const response = await this.instance.request(axiosConfig);
|
|
52
|
+
return {
|
|
53
|
+
data: response.data,
|
|
54
|
+
status: response.status,
|
|
55
|
+
headers: response.headers,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 获取 Axios 实例
|
|
60
|
+
*
|
|
61
|
+
* 用于直接访问 Axios 实例进行高级操作
|
|
62
|
+
*
|
|
63
|
+
* @returns Axios 实例
|
|
64
|
+
*/
|
|
65
|
+
getAxiosInstance() {
|
|
66
|
+
return this.instance;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Taro 适配器
|
|
72
|
+
*
|
|
73
|
+
* 使用 Taro.request 实现 HttpAdapter 接口
|
|
74
|
+
* 适用于 Taro 小程序项目
|
|
75
|
+
*
|
|
76
|
+
* @module adapters/TaroAdapter
|
|
77
|
+
*/
|
|
78
|
+
/**
|
|
79
|
+
* Taro 适配器
|
|
80
|
+
*
|
|
81
|
+
* 将 Taro.request 封装为统一的 HttpAdapter 接口
|
|
82
|
+
*/
|
|
83
|
+
class TaroAdapter {
|
|
84
|
+
/**
|
|
85
|
+
* 创建 Taro 适配器实例
|
|
86
|
+
*
|
|
87
|
+
* @param config - 适配器配置
|
|
88
|
+
*/
|
|
89
|
+
constructor(config) {
|
|
90
|
+
this.baseURL = config.baseURL;
|
|
91
|
+
this.timeout = config.timeout || 30000;
|
|
92
|
+
this.defaultHeaders = {
|
|
93
|
+
'Content-Type': 'application/json',
|
|
94
|
+
...(config.headers || {}),
|
|
95
|
+
};
|
|
96
|
+
this.taroRequest = config.taroRequest;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 发起 HTTP 请求
|
|
100
|
+
*
|
|
101
|
+
* @param config - 请求配置
|
|
102
|
+
* @returns Promise 响应数据
|
|
103
|
+
*/
|
|
104
|
+
async request(config) {
|
|
105
|
+
const fullUrl = this.resolveUrl(config.url, config.params);
|
|
106
|
+
const res = await this.taroRequest({
|
|
107
|
+
url: fullUrl,
|
|
108
|
+
method: (config.method || 'GET'),
|
|
109
|
+
data: config.data,
|
|
110
|
+
header: {
|
|
111
|
+
...this.defaultHeaders,
|
|
112
|
+
...(config.headers || {}),
|
|
113
|
+
},
|
|
114
|
+
timeout: config.timeout || this.timeout,
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
data: res.data,
|
|
118
|
+
status: res.statusCode,
|
|
119
|
+
headers: res.header,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 解析完整 URL
|
|
124
|
+
*
|
|
125
|
+
* 处理相对路径和查询参数
|
|
126
|
+
*
|
|
127
|
+
* @param url - 请求 URL
|
|
128
|
+
* @param params - 查询参数
|
|
129
|
+
* @returns 完整 URL
|
|
130
|
+
*/
|
|
131
|
+
resolveUrl(url, params) {
|
|
132
|
+
// 如果是绝对路径,直接使用;否则拼接 baseURL
|
|
133
|
+
const fullUrl = url.startsWith('http') ? url : `${this.baseURL}${url}`;
|
|
134
|
+
// 如果没有查询参数,直接返回
|
|
135
|
+
if (!params || Object.keys(params).length === 0) {
|
|
136
|
+
return fullUrl;
|
|
137
|
+
}
|
|
138
|
+
// 序列化查询参数
|
|
139
|
+
const queryParts = [];
|
|
140
|
+
for (const key of Object.keys(params)) {
|
|
141
|
+
const value = params[key];
|
|
142
|
+
if (value !== undefined && value !== null) {
|
|
143
|
+
queryParts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (queryParts.length === 0) {
|
|
147
|
+
return fullUrl;
|
|
148
|
+
}
|
|
149
|
+
const queryString = queryParts.join('&');
|
|
150
|
+
return `${fullUrl}${fullUrl.includes('?') ? '&' : '?'}${queryString}`;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* 创建 Taro Fetch 包装器
|
|
155
|
+
*
|
|
156
|
+
* 将 Taro.request 包装为类似 fetch 的函数
|
|
157
|
+
* 用于 TimeSyncService 进行时间同步
|
|
158
|
+
*
|
|
159
|
+
* @param taroRequest - Taro.request 函数引用
|
|
160
|
+
* @returns FetchFunction 类型的函数
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* import Taro from '@tarojs/taro';
|
|
165
|
+
* import { createTaroFetch } from '@be-link/http';
|
|
166
|
+
*
|
|
167
|
+
* const fetchFn = createTaroFetch(Taro.request);
|
|
168
|
+
* const timeSyncService = new TimeSyncService(config, fetchFn);
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
function createTaroFetch(taroRequest) {
|
|
172
|
+
return async (url, options) => {
|
|
173
|
+
const method = (options?.method?.toUpperCase() || 'GET');
|
|
174
|
+
const res = await taroRequest({
|
|
175
|
+
url,
|
|
176
|
+
method,
|
|
177
|
+
// POST 请求需要传递 data,避免 "Body cannot be empty" 错误
|
|
178
|
+
data: method === 'POST' ? {} : undefined,
|
|
179
|
+
});
|
|
180
|
+
return {
|
|
181
|
+
ok: res.statusCode >= 200 && res.statusCode < 300,
|
|
182
|
+
status: res.statusCode,
|
|
183
|
+
json: async () => res.data,
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* 通用拦截器核心逻辑
|
|
190
|
+
*
|
|
191
|
+
* 提供与具体 HTTP 库无关的请求/响应处理函数
|
|
192
|
+
* 支持 Axios 和 Taro.request 适配器复用
|
|
193
|
+
*
|
|
194
|
+
* @module interceptors/core
|
|
195
|
+
*/
|
|
196
|
+
/**
|
|
197
|
+
* 处理请求配置
|
|
198
|
+
*
|
|
199
|
+
* 在请求发出前对配置进行处理,包括:
|
|
200
|
+
* 1. 确保时间同步
|
|
201
|
+
* 2. 设置默认 Content-Type
|
|
202
|
+
* 3. 添加用户 ID 到请求头
|
|
203
|
+
* 4. 加密并添加 Token 到请求头
|
|
204
|
+
* 5. 调用自定义请求拦截器
|
|
205
|
+
*
|
|
206
|
+
* @param config - 请求配置
|
|
207
|
+
* @param options - 全局请求选项
|
|
208
|
+
* @param timeSyncService - 时间同步服务(可选)
|
|
209
|
+
* @param encryptionService - 加密服务(可选)
|
|
210
|
+
* @returns 处理后的请求配置
|
|
211
|
+
*/
|
|
212
|
+
async function processRequest(config, options, timeSyncService, encryptionService) {
|
|
213
|
+
// 获取 header 名称,使用默认值
|
|
214
|
+
const tokenHeaderName = options.tokenHeaderName || 'X-BeLink-Token';
|
|
215
|
+
const userIdHeaderName = options.userIdHeaderName || 'X-BeLink-UserId';
|
|
216
|
+
// 确保 headers 对象存在
|
|
217
|
+
config.headers = config.headers || {};
|
|
218
|
+
// 步骤 1: 确保时间同步
|
|
219
|
+
// 在请求发出前检查并同步服务器时间,确保后续 Token 加密使用正确的时间戳
|
|
220
|
+
if (timeSyncService) {
|
|
221
|
+
await timeSyncService.ensureSync();
|
|
222
|
+
}
|
|
223
|
+
// 步骤 2: 设置默认 Content-Type
|
|
224
|
+
// 如果请求未指定 Content-Type,默认使用 JSON 格式
|
|
225
|
+
if (!config.headers['Content-Type']) {
|
|
226
|
+
config.headers['Content-Type'] = 'application/json';
|
|
227
|
+
}
|
|
228
|
+
// 步骤 3: 添加用户 ID
|
|
229
|
+
// 调用用户配置的 getUserId 函数获取用户 ID,添加到请求头
|
|
230
|
+
if (options.getUserId) {
|
|
231
|
+
const userId = options.getUserId();
|
|
232
|
+
if (userId) {
|
|
233
|
+
config.headers[userIdHeaderName] = userId;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// 步骤 4: 添加 Token
|
|
237
|
+
// 根据是否配置了加密服务,决定是否对 Token 进行加密
|
|
238
|
+
if (options.getToken) {
|
|
239
|
+
const token = options.getToken();
|
|
240
|
+
if (token) {
|
|
241
|
+
config.headers[tokenHeaderName] = encryptionService ? encryptionService.encryptToken(token) : token;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return config;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* 处理响应数据
|
|
248
|
+
*
|
|
249
|
+
* 在收到响应后对数据进行处理,调用自定义响应拦截器
|
|
250
|
+
*
|
|
251
|
+
* @param data - 响应数据
|
|
252
|
+
* @param options - 全局请求选项
|
|
253
|
+
* @returns 处理后的响应数据
|
|
254
|
+
*/
|
|
255
|
+
function processResponse(data, options) {
|
|
256
|
+
// 调用自定义响应拦截器
|
|
257
|
+
// 允许用户对响应数据进行进一步处理
|
|
258
|
+
if (options.onResponse) {
|
|
259
|
+
return options.onResponse(data);
|
|
260
|
+
}
|
|
261
|
+
return data;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* 处理错误
|
|
265
|
+
*
|
|
266
|
+
* 在请求出错时进行处理,支持自定义错误处理和业务错误检查
|
|
267
|
+
*
|
|
268
|
+
* @param error - 错误对象
|
|
269
|
+
* @param options - 全局请求选项
|
|
270
|
+
* @throws 处理后的错误
|
|
271
|
+
*/
|
|
272
|
+
function processError(error, options) {
|
|
273
|
+
// 优先调用自定义错误处理
|
|
274
|
+
// 如果用户配置了 onError,由用户自行处理错误
|
|
275
|
+
if (options.onError) {
|
|
276
|
+
const result = options.onError(error);
|
|
277
|
+
// 如果 onError 返回了值而不是抛出错误,我们继续抛出
|
|
278
|
+
throw result ?? error;
|
|
279
|
+
}
|
|
280
|
+
// 获取响应数据(如果有)
|
|
281
|
+
const responseData = error?.response?.data;
|
|
282
|
+
// 检查业务错误
|
|
283
|
+
// 业务错误:HTTP 状态码可能是 200,但响应体中 success === false
|
|
284
|
+
if (responseData && typeof responseData === 'object' && !responseData.success) {
|
|
285
|
+
// 创建业务错误对象
|
|
286
|
+
const bizError = new Error(responseData.message || '接口请求失败');
|
|
287
|
+
// 附加原始响应信息,方便调试
|
|
288
|
+
bizError.response = error.response;
|
|
289
|
+
bizError.data = responseData;
|
|
290
|
+
throw bizError;
|
|
291
|
+
}
|
|
292
|
+
// 其他错误(网络错误、超时等)直接抛出
|
|
293
|
+
throw error;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* 检查响应状态并处理业务错误
|
|
297
|
+
*
|
|
298
|
+
* @param data - 响应数据
|
|
299
|
+
* @param status - HTTP 状态码
|
|
300
|
+
* @returns 处理后的响应数据
|
|
301
|
+
*/
|
|
302
|
+
function checkResponseStatus(data, status) {
|
|
303
|
+
// 检查 HTTP 状态码
|
|
304
|
+
if (status < 200 || status >= 300) {
|
|
305
|
+
const error = new Error(`HTTP Error: ${status}`);
|
|
306
|
+
error.status = status;
|
|
307
|
+
error.data = data;
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
// 检查业务错误(如果响应是标准格式)
|
|
311
|
+
const responseData = data;
|
|
312
|
+
if (responseData && typeof responseData === 'object' && 'success' in responseData && !responseData.success) {
|
|
313
|
+
const bizError = new Error(responseData.message || '接口请求失败');
|
|
314
|
+
bizError.data = responseData;
|
|
315
|
+
bizError.errorType = responseData.errorType;
|
|
316
|
+
throw bizError;
|
|
317
|
+
}
|
|
318
|
+
return data;
|
|
319
|
+
}
|
|
320
|
+
|
|
8
321
|
/**
|
|
9
322
|
* 时间同步服务
|
|
10
323
|
*
|
|
@@ -25,7 +338,7 @@ const STORAGE_KEYS = {
|
|
|
25
338
|
CLIENT_TIME: 'belink_client_time',
|
|
26
339
|
};
|
|
27
340
|
/**
|
|
28
|
-
*
|
|
341
|
+
* 检测是否为浏览器环境(支持 localStorage)
|
|
29
342
|
*/
|
|
30
343
|
function isBrowser() {
|
|
31
344
|
return typeof window !== 'undefined' && typeof localStorage !== 'undefined';
|
|
@@ -71,8 +384,21 @@ function getPerformanceNow() {
|
|
|
71
384
|
class TimeSyncService {
|
|
72
385
|
/**
|
|
73
386
|
* 创建时间同步服务实例
|
|
387
|
+
*
|
|
388
|
+
* @param config - 时间同步配置
|
|
389
|
+
* @param fetchFn - 自定义 fetch 函数(可选),用于支持 Taro 等非浏览器环境
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* ```ts
|
|
393
|
+
* // 使用默认 fetch
|
|
394
|
+
* const timeSync = new TimeSyncService({ syncUrl: 'https://api.example.com/time' });
|
|
395
|
+
*
|
|
396
|
+
* // 使用 Taro.request
|
|
397
|
+
* import { createTaroFetch } from '@be-link/http';
|
|
398
|
+
* const timeSync = new TimeSyncService(config, createTaroFetch(Taro.request));
|
|
399
|
+
* ```
|
|
74
400
|
*/
|
|
75
|
-
constructor(config) {
|
|
401
|
+
constructor(config, fetchFn) {
|
|
76
402
|
/**
|
|
77
403
|
* 同步时的服务器时间(内存存储)
|
|
78
404
|
* 用于计算调整后的时间
|
|
@@ -93,6 +419,22 @@ class TimeSyncService {
|
|
|
93
419
|
syncGapTime: 50 * 1000, // 默认 50 秒
|
|
94
420
|
...config,
|
|
95
421
|
};
|
|
422
|
+
// 记录是否使用了自定义 fetchFn
|
|
423
|
+
this.hasCustomFetch = !!fetchFn;
|
|
424
|
+
// 使用传入的 fetchFn 或默认的 fetch
|
|
425
|
+
this.fetchFn = fetchFn || this.defaultFetch.bind(this);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* 默认的 fetch 实现
|
|
429
|
+
* 使用浏览器原生 fetch API
|
|
430
|
+
*/
|
|
431
|
+
async defaultFetch(url, options) {
|
|
432
|
+
const response = await fetch(url, options);
|
|
433
|
+
return {
|
|
434
|
+
ok: response.ok,
|
|
435
|
+
status: response.status,
|
|
436
|
+
json: () => response.json(),
|
|
437
|
+
};
|
|
96
438
|
}
|
|
97
439
|
/**
|
|
98
440
|
* 确保时间已同步
|
|
@@ -106,7 +448,13 @@ class TimeSyncService {
|
|
|
106
448
|
* - 避免多个并发请求同时触发多次时间同步
|
|
107
449
|
*/
|
|
108
450
|
async ensureSync() {
|
|
109
|
-
|
|
451
|
+
// 检查是否启用
|
|
452
|
+
if (!this.config.enabled) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
// 环境检测:如果没有自定义 fetchFn 且不是浏览器环境,跳过同步
|
|
456
|
+
// 如果有自定义 fetchFn(如 Taro.request),则允许在任何环境执行
|
|
457
|
+
if (!this.hasCustomFetch && !isBrowser()) {
|
|
110
458
|
return;
|
|
111
459
|
}
|
|
112
460
|
// 如果已有同步请求正在进行,等待它完成
|
|
@@ -136,7 +484,12 @@ class TimeSyncService {
|
|
|
136
484
|
* - 同步完成后清除锁,允许后续同步请求
|
|
137
485
|
*/
|
|
138
486
|
async sync() {
|
|
139
|
-
|
|
487
|
+
// 检查 syncUrl 是否配置
|
|
488
|
+
if (!this.config.syncUrl) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
// 环境检测:如果没有自定义 fetchFn 且不是浏览器环境,跳过同步
|
|
492
|
+
if (!this.hasCustomFetch && !isBrowser()) {
|
|
140
493
|
return;
|
|
141
494
|
}
|
|
142
495
|
// 如果已有同步请求正在进行,等待它完成
|
|
@@ -161,7 +514,8 @@ class TimeSyncService {
|
|
|
161
514
|
try {
|
|
162
515
|
// 记录请求发起时的 performance.now()
|
|
163
516
|
const requestStartTime = getPerformanceNow();
|
|
164
|
-
|
|
517
|
+
// 使用注入的 fetch 函数
|
|
518
|
+
const response = await this.fetchFn(this.config.syncUrl, { method: 'POST' });
|
|
165
519
|
if (!response.ok) {
|
|
166
520
|
console.error('[TimeSyncService] Sync failed with status:', response.status);
|
|
167
521
|
this.clear();
|
|
@@ -179,11 +533,13 @@ class TimeSyncService {
|
|
|
179
533
|
// 存储到内存(使用 performance.now())
|
|
180
534
|
this.syncServerTime = serverTime + networkDelay;
|
|
181
535
|
this.syncPerformanceTime = requestEndTime;
|
|
182
|
-
// 同时存储到 localStorage
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
536
|
+
// 同时存储到 localStorage(用于调试和日志),仅在浏览器环境下
|
|
537
|
+
if (isBrowser()) {
|
|
538
|
+
const serverTimeKey = getStorageKey(this.config.storagePrefix, STORAGE_KEYS.SERVER_TIME);
|
|
539
|
+
const clientTimeKey = getStorageKey(this.config.storagePrefix, STORAGE_KEYS.CLIENT_TIME);
|
|
540
|
+
localStorage.setItem(serverTimeKey, String(this.syncServerTime));
|
|
541
|
+
localStorage.setItem(clientTimeKey, String(Date.now()));
|
|
542
|
+
}
|
|
187
543
|
}
|
|
188
544
|
catch (error) {
|
|
189
545
|
console.error('[TimeSyncService] Failed to sync time:', error);
|
|
@@ -388,185 +744,16 @@ class EncryptionService {
|
|
|
388
744
|
}
|
|
389
745
|
}
|
|
390
746
|
|
|
391
|
-
/**
|
|
392
|
-
* 请求拦截器
|
|
393
|
-
*
|
|
394
|
-
* 在请求发出前对请求进行处理,包括:
|
|
395
|
-
* - 时间同步
|
|
396
|
-
* - 设置默认请求头
|
|
397
|
-
* - 添加用户 ID
|
|
398
|
-
* - Token 加密和添加
|
|
399
|
-
* - 调用自定义拦截器
|
|
400
|
-
*
|
|
401
|
-
* @module interceptors/request
|
|
402
|
-
*/
|
|
403
|
-
/**
|
|
404
|
-
* 设置请求拦截器
|
|
405
|
-
*
|
|
406
|
-
* 为 Axios 实例添加请求拦截器,处理请求前的通用逻辑
|
|
407
|
-
*
|
|
408
|
-
* 拦截器执行顺序:
|
|
409
|
-
* 1. 确保时间同步(如果配置了 TimeSyncService)
|
|
410
|
-
* 2. 设置默认 Content-Type
|
|
411
|
-
* 3. 添加用户 ID 到请求头
|
|
412
|
-
* 4. 加密并添加 Token 到请求头
|
|
413
|
-
* 5. 调用自定义请求拦截器
|
|
414
|
-
*
|
|
415
|
-
* @param instance - Axios 实例
|
|
416
|
-
* @param options - 请求配置选项
|
|
417
|
-
* @param timeSyncService - 时间同步服务实例(可选)
|
|
418
|
-
* @param encryptionService - 加密服务实例(可选)
|
|
419
|
-
*
|
|
420
|
-
* @example
|
|
421
|
-
* ```ts
|
|
422
|
-
* const instance = axios.create({ baseURL: 'https://api.example.com' });
|
|
423
|
-
*
|
|
424
|
-
* setRequestInterceptor(
|
|
425
|
-
* instance,
|
|
426
|
-
* {
|
|
427
|
-
* baseURL: 'https://api.example.com',
|
|
428
|
-
* getToken: () => localStorage.getItem('token'),
|
|
429
|
-
* getUserId: () => localStorage.getItem('userId'),
|
|
430
|
-
* },
|
|
431
|
-
* timeSyncService,
|
|
432
|
-
* encryptionService,
|
|
433
|
-
* );
|
|
434
|
-
* ```
|
|
435
|
-
*/
|
|
436
|
-
function setRequestInterceptor(instance, options, timeSyncService, encryptionService) {
|
|
437
|
-
// 获取 header 名称,使用默认值
|
|
438
|
-
const tokenHeaderName = options.tokenHeaderName || 'X-BeLink-Token';
|
|
439
|
-
const userIdHeaderName = options.userIdHeaderName || 'X-BeLink-UserId';
|
|
440
|
-
instance.interceptors.request.use(async (config) => {
|
|
441
|
-
// 步骤 1: 确保时间同步
|
|
442
|
-
// 在请求发出前检查并同步服务器时间,确保后续 Token 加密使用正确的时间戳
|
|
443
|
-
if (timeSyncService) {
|
|
444
|
-
await timeSyncService.ensureSync();
|
|
445
|
-
}
|
|
446
|
-
// 步骤 2: 设置默认 Content-Type
|
|
447
|
-
// 如果请求未指定 Content-Type,默认使用 JSON 格式
|
|
448
|
-
if (!config.headers['Content-Type']) {
|
|
449
|
-
config.headers['Content-Type'] = 'application/json';
|
|
450
|
-
}
|
|
451
|
-
// 步骤 3: 添加用户 ID
|
|
452
|
-
// 调用用户配置的 getUserId 函数获取用户 ID,添加到请求头
|
|
453
|
-
if (options.getUserId) {
|
|
454
|
-
const userId = options.getUserId();
|
|
455
|
-
if (userId) {
|
|
456
|
-
config.headers[userIdHeaderName] = userId;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
// 步骤 4: 添加 Token
|
|
460
|
-
// 根据是否配置了加密服务,决定是否对 Token 进行加密
|
|
461
|
-
if (options.getToken) {
|
|
462
|
-
const token = options.getToken();
|
|
463
|
-
if (token) {
|
|
464
|
-
config.headers[tokenHeaderName] = encryptionService ? encryptionService.encryptToken(token) : token;
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
// 步骤 5: 调用自定义请求拦截器
|
|
468
|
-
// 允许用户进一步自定义请求配置
|
|
469
|
-
if (options.onRequest) {
|
|
470
|
-
return options.onRequest(config);
|
|
471
|
-
}
|
|
472
|
-
return config;
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
/**
|
|
477
|
-
* 响应拦截器
|
|
478
|
-
*
|
|
479
|
-
* 在收到响应后对响应进行处理,包括:
|
|
480
|
-
* - 提取响应数据
|
|
481
|
-
* - 调用自定义响应拦截器
|
|
482
|
-
* - 统一错误处理
|
|
483
|
-
*
|
|
484
|
-
* @module interceptors/response
|
|
485
|
-
*/
|
|
486
|
-
/**
|
|
487
|
-
* 设置响应拦截器
|
|
488
|
-
*
|
|
489
|
-
* 为 Axios 实例添加响应拦截器,处理响应后的通用逻辑
|
|
490
|
-
*
|
|
491
|
-
* 成功响应处理:
|
|
492
|
-
* 1. 提取响应数据(response.data)
|
|
493
|
-
* 2. 调用自定义响应拦截器(如果配置)
|
|
494
|
-
* 3. 返回处理后的数据
|
|
495
|
-
*
|
|
496
|
-
* 错误响应处理:
|
|
497
|
-
* 1. 调用自定义错误处理(如果配置)
|
|
498
|
-
* 2. 检查业务错误(success === false)
|
|
499
|
-
* 3. 抛出错误
|
|
500
|
-
*
|
|
501
|
-
* @param instance - Axios 实例
|
|
502
|
-
* @param options - 请求配置选项
|
|
503
|
-
*
|
|
504
|
-
* @example
|
|
505
|
-
* ```ts
|
|
506
|
-
* const instance = axios.create({ baseURL: 'https://api.example.com' });
|
|
507
|
-
*
|
|
508
|
-
* setResponseInterceptor(instance, {
|
|
509
|
-
* baseURL: 'https://api.example.com',
|
|
510
|
-
* onResponse: (data) => {
|
|
511
|
-
* console.log('响应数据:', data);
|
|
512
|
-
* return data;
|
|
513
|
-
* },
|
|
514
|
-
* onError: (error) => {
|
|
515
|
-
* if (error.response?.status === 401) {
|
|
516
|
-
* // 处理未授权错误
|
|
517
|
-
* window.location.href = '/login';
|
|
518
|
-
* }
|
|
519
|
-
* throw error;
|
|
520
|
-
* },
|
|
521
|
-
* });
|
|
522
|
-
* ```
|
|
523
|
-
*/
|
|
524
|
-
function setResponseInterceptor(instance, options) {
|
|
525
|
-
instance.interceptors.response.use(
|
|
526
|
-
// 成功响应处理
|
|
527
|
-
(response) => {
|
|
528
|
-
// 提取响应数据(Axios 的响应数据在 response.data 中)
|
|
529
|
-
const data = response.data;
|
|
530
|
-
// 调用自定义响应拦截器
|
|
531
|
-
// 允许用户对响应数据进行进一步处理
|
|
532
|
-
if (options.onResponse) {
|
|
533
|
-
return options.onResponse(data);
|
|
534
|
-
}
|
|
535
|
-
return data;
|
|
536
|
-
},
|
|
537
|
-
// 错误响应处理
|
|
538
|
-
(error) => {
|
|
539
|
-
// 优先调用自定义错误处理
|
|
540
|
-
// 如果用户配置了 onError,由用户自行处理错误
|
|
541
|
-
if (options.onError) {
|
|
542
|
-
return options.onError(error);
|
|
543
|
-
}
|
|
544
|
-
// 获取响应数据(如果有)
|
|
545
|
-
const responseData = error?.response?.data;
|
|
546
|
-
// 检查业务错误
|
|
547
|
-
// 业务错误:HTTP 状态码可能是 200,但响应体中 success === false
|
|
548
|
-
if (responseData && typeof responseData === 'object' && !responseData.success) {
|
|
549
|
-
// 创建业务错误对象
|
|
550
|
-
const bizError = new Error(responseData.message || '接口请求失败');
|
|
551
|
-
// 附加原始响应信息,方便调试
|
|
552
|
-
bizError.response = error.response;
|
|
553
|
-
bizError.data = responseData;
|
|
554
|
-
throw bizError;
|
|
555
|
-
}
|
|
556
|
-
// 其他错误(网络错误、超时等)直接抛出
|
|
557
|
-
throw error;
|
|
558
|
-
});
|
|
559
|
-
}
|
|
560
|
-
|
|
561
747
|
/**
|
|
562
748
|
* BeLinkHttp 请求客户端
|
|
563
749
|
*
|
|
564
750
|
* 单例模式的 HTTP 请求客户端
|
|
565
751
|
* 支持时间同步和 Token 加密
|
|
752
|
+
* 支持 Axios 和 Taro.request 两种请求引擎
|
|
566
753
|
*
|
|
567
754
|
* @module BeLinkHttp
|
|
568
755
|
*
|
|
569
|
-
* @example
|
|
756
|
+
* @example Axios 模式(默认)
|
|
570
757
|
* ```ts
|
|
571
758
|
* import { beLinkHttp } from '@be-link/http';
|
|
572
759
|
*
|
|
@@ -581,25 +768,49 @@ function setResponseInterceptor(instance, options) {
|
|
|
581
768
|
* // 发起请求
|
|
582
769
|
* const data = await beLinkHttp.get('/api/users');
|
|
583
770
|
* ```
|
|
771
|
+
*
|
|
772
|
+
* @example Taro 模式
|
|
773
|
+
* ```ts
|
|
774
|
+
* import { beLinkHttp } from '@be-link/http';
|
|
775
|
+
* import Taro from '@tarojs/taro';
|
|
776
|
+
*
|
|
777
|
+
* // 初始化
|
|
778
|
+
* beLinkHttp.init({
|
|
779
|
+
* adapter: 'taro',
|
|
780
|
+
* taroRequest: Taro.request,
|
|
781
|
+
* baseURL: 'https://api.example.com',
|
|
782
|
+
* getToken: () => Taro.getStorageSync('token'),
|
|
783
|
+
* });
|
|
784
|
+
*
|
|
785
|
+
* // 发起请求(使用方式完全一致)
|
|
786
|
+
* const data = await beLinkHttp.get('/api/users');
|
|
787
|
+
* ```
|
|
584
788
|
*/
|
|
585
789
|
/**
|
|
586
790
|
* BeLinkHttp 单例类
|
|
587
791
|
*
|
|
588
792
|
* 提供统一的 HTTP 请求接口,支持:
|
|
793
|
+
* - 多适配器(Axios / Taro)
|
|
589
794
|
* - 时间同步
|
|
590
795
|
* - Token 加密
|
|
591
796
|
* - 请求/响应拦截
|
|
592
797
|
*/
|
|
593
798
|
class BeLinkHttp {
|
|
594
799
|
constructor() {
|
|
595
|
-
/**
|
|
596
|
-
this.
|
|
800
|
+
/** HTTP 适配器实例 */
|
|
801
|
+
this.adapter = null;
|
|
597
802
|
/** 时间同步服务 */
|
|
598
803
|
this.timeSyncService = null;
|
|
599
804
|
/** 加密服务 */
|
|
600
805
|
this.encryptionService = null;
|
|
806
|
+
/** 请求配置选项 */
|
|
807
|
+
this.options = null;
|
|
601
808
|
/** 是否已初始化 */
|
|
602
809
|
this.initialized = false;
|
|
810
|
+
/** 动态设置的 Token */
|
|
811
|
+
this._token = null;
|
|
812
|
+
/** 动态设置的 UserId */
|
|
813
|
+
this._userId = null;
|
|
603
814
|
}
|
|
604
815
|
/**
|
|
605
816
|
* 初始化请求客户端
|
|
@@ -608,7 +819,7 @@ class BeLinkHttp {
|
|
|
608
819
|
*
|
|
609
820
|
* @param options - 请求配置选项
|
|
610
821
|
*
|
|
611
|
-
* @example
|
|
822
|
+
* @example Axios 模式
|
|
612
823
|
* ```ts
|
|
613
824
|
* beLinkHttp.init({
|
|
614
825
|
* baseURL: 'https://api.example.com',
|
|
@@ -624,36 +835,61 @@ class BeLinkHttp {
|
|
|
624
835
|
* getUserId: () => localStorage.getItem('userId'),
|
|
625
836
|
* });
|
|
626
837
|
* ```
|
|
838
|
+
*
|
|
839
|
+
* @example Taro 模式
|
|
840
|
+
* ```ts
|
|
841
|
+
* import Taro from '@tarojs/taro';
|
|
842
|
+
*
|
|
843
|
+
* beLinkHttp.init({
|
|
844
|
+
* adapter: 'taro',
|
|
845
|
+
* taroRequest: Taro.request,
|
|
846
|
+
* baseURL: 'https://api.example.com',
|
|
847
|
+
* getToken: () => Taro.getStorageSync('token'),
|
|
848
|
+
* });
|
|
849
|
+
* ```
|
|
627
850
|
*/
|
|
628
851
|
init(options) {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
852
|
+
this.options = options;
|
|
853
|
+
const { baseURL, timeout = 30000, headers = {}, timeSync, encryption, adapter = 'axios' } = options;
|
|
854
|
+
// 创建适配器
|
|
855
|
+
if (adapter === 'taro') {
|
|
856
|
+
if (!options.taroRequest) {
|
|
857
|
+
throw new Error('[BeLinkHttp] 使用 taro 适配器时必须传入 taroRequest');
|
|
858
|
+
}
|
|
859
|
+
this.adapter = new TaroAdapter({
|
|
860
|
+
baseURL,
|
|
861
|
+
timeout,
|
|
862
|
+
headers,
|
|
863
|
+
taroRequest: options.taroRequest,
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
else {
|
|
867
|
+
this.adapter = new AxiosAdapter({
|
|
868
|
+
baseURL,
|
|
869
|
+
timeout,
|
|
870
|
+
headers,
|
|
871
|
+
});
|
|
872
|
+
}
|
|
639
873
|
// 创建时间同步服务
|
|
640
874
|
if (timeSync?.syncUrl) {
|
|
641
|
-
|
|
875
|
+
let fetchFn;
|
|
876
|
+
// 如果使用 Taro 适配器,创建 Taro Fetch 包装器
|
|
877
|
+
if (adapter === 'taro' && options.taroRequest) {
|
|
878
|
+
fetchFn = createTaroFetch(options.taroRequest);
|
|
879
|
+
}
|
|
880
|
+
this.timeSyncService = new TimeSyncService(timeSync, fetchFn);
|
|
642
881
|
}
|
|
643
882
|
// 创建加密服务
|
|
644
883
|
if (encryption?.key && encryption?.iv) {
|
|
645
884
|
this.encryptionService = new EncryptionService(encryption, this.timeSyncService);
|
|
646
885
|
}
|
|
647
|
-
// 设置拦截器
|
|
648
|
-
setRequestInterceptor(this.instance, options, this.timeSyncService, this.encryptionService);
|
|
649
|
-
setResponseInterceptor(this.instance, options);
|
|
650
886
|
this.initialized = true;
|
|
651
887
|
}
|
|
652
888
|
/**
|
|
653
889
|
* 检查是否已初始化
|
|
654
890
|
*/
|
|
655
891
|
checkInitialized() {
|
|
656
|
-
if (!this.initialized || !this.
|
|
892
|
+
if (!this.initialized || !this.adapter) {
|
|
657
893
|
throw new Error('[BeLinkHttp] 请先调用 init() 方法进行初始化');
|
|
658
894
|
}
|
|
659
895
|
}
|
|
@@ -661,7 +897,7 @@ class BeLinkHttp {
|
|
|
661
897
|
* GET 请求
|
|
662
898
|
*
|
|
663
899
|
* @param url - 请求 URL
|
|
664
|
-
* @param config -
|
|
900
|
+
* @param config - 可选的请求配置
|
|
665
901
|
* @returns Promise 响应数据
|
|
666
902
|
*
|
|
667
903
|
* @example
|
|
@@ -671,15 +907,14 @@ class BeLinkHttp {
|
|
|
671
907
|
* ```
|
|
672
908
|
*/
|
|
673
909
|
async get(url, config) {
|
|
674
|
-
this.
|
|
675
|
-
return this.instance.get(url, config);
|
|
910
|
+
return this.request({ ...config, url, method: 'GET' });
|
|
676
911
|
}
|
|
677
912
|
/**
|
|
678
913
|
* POST 请求
|
|
679
914
|
*
|
|
680
915
|
* @param url - 请求 URL
|
|
681
916
|
* @param data - 请求体数据
|
|
682
|
-
* @param config -
|
|
917
|
+
* @param config - 可选的请求配置
|
|
683
918
|
* @returns Promise 响应数据
|
|
684
919
|
*
|
|
685
920
|
* @example
|
|
@@ -688,15 +923,14 @@ class BeLinkHttp {
|
|
|
688
923
|
* ```
|
|
689
924
|
*/
|
|
690
925
|
async post(url, data, config) {
|
|
691
|
-
this.
|
|
692
|
-
return this.instance.post(url, data, config);
|
|
926
|
+
return this.request({ ...config, url, method: 'POST', data });
|
|
693
927
|
}
|
|
694
928
|
/**
|
|
695
929
|
* PUT 请求
|
|
696
930
|
*
|
|
697
931
|
* @param url - 请求 URL
|
|
698
932
|
* @param data - 请求体数据
|
|
699
|
-
* @param config -
|
|
933
|
+
* @param config - 可选的请求配置
|
|
700
934
|
* @returns Promise 响应数据
|
|
701
935
|
*
|
|
702
936
|
* @example
|
|
@@ -705,15 +939,14 @@ class BeLinkHttp {
|
|
|
705
939
|
* ```
|
|
706
940
|
*/
|
|
707
941
|
async put(url, data, config) {
|
|
708
|
-
this.
|
|
709
|
-
return this.instance.put(url, data, config);
|
|
942
|
+
return this.request({ ...config, url, method: 'PUT', data });
|
|
710
943
|
}
|
|
711
944
|
/**
|
|
712
945
|
* PATCH 请求
|
|
713
946
|
*
|
|
714
947
|
* @param url - 请求 URL
|
|
715
948
|
* @param data - 请求体数据
|
|
716
|
-
* @param config -
|
|
949
|
+
* @param config - 可选的请求配置
|
|
717
950
|
* @returns Promise 响应数据
|
|
718
951
|
*
|
|
719
952
|
* @example
|
|
@@ -722,14 +955,13 @@ class BeLinkHttp {
|
|
|
722
955
|
* ```
|
|
723
956
|
*/
|
|
724
957
|
async patch(url, data, config) {
|
|
725
|
-
this.
|
|
726
|
-
return this.instance.patch(url, data, config);
|
|
958
|
+
return this.request({ ...config, url, method: 'PATCH', data });
|
|
727
959
|
}
|
|
728
960
|
/**
|
|
729
961
|
* DELETE 请求
|
|
730
962
|
*
|
|
731
963
|
* @param url - 请求 URL
|
|
732
|
-
* @param config -
|
|
964
|
+
* @param config - 可选的请求配置
|
|
733
965
|
* @returns Promise 响应数据
|
|
734
966
|
*
|
|
735
967
|
* @example
|
|
@@ -738,19 +970,18 @@ class BeLinkHttp {
|
|
|
738
970
|
* ```
|
|
739
971
|
*/
|
|
740
972
|
async delete(url, config) {
|
|
741
|
-
this.
|
|
742
|
-
return this.instance.delete(url, config);
|
|
973
|
+
return this.request({ ...config, url, method: 'DELETE' });
|
|
743
974
|
}
|
|
744
975
|
/**
|
|
745
976
|
* 通用请求方法
|
|
746
977
|
*
|
|
747
|
-
* @param config -
|
|
978
|
+
* @param config - 请求配置
|
|
748
979
|
* @returns Promise 响应数据
|
|
749
980
|
*
|
|
750
981
|
* @example
|
|
751
982
|
* ```ts
|
|
752
983
|
* const result = await beLinkHttp.request({
|
|
753
|
-
* method: '
|
|
984
|
+
* method: 'POST',
|
|
754
985
|
* url: '/api/users',
|
|
755
986
|
* data: { name: '张三' },
|
|
756
987
|
* headers: { 'X-Custom': 'value' },
|
|
@@ -759,7 +990,25 @@ class BeLinkHttp {
|
|
|
759
990
|
*/
|
|
760
991
|
async request(config) {
|
|
761
992
|
this.checkInitialized();
|
|
762
|
-
|
|
993
|
+
try {
|
|
994
|
+
// 创建带有动态 token/userId 获取函数的 options
|
|
995
|
+
const optionsWithDynamicAuth = {
|
|
996
|
+
...this.options,
|
|
997
|
+
getToken: () => this.getToken(),
|
|
998
|
+
getUserId: () => this.getUserId(),
|
|
999
|
+
};
|
|
1000
|
+
// 处理请求(应用拦截器逻辑)
|
|
1001
|
+
const processedConfig = await processRequest({ ...config }, optionsWithDynamicAuth, this.timeSyncService, this.encryptionService);
|
|
1002
|
+
// 发起请求
|
|
1003
|
+
const response = await this.adapter.request(processedConfig);
|
|
1004
|
+
// 检查响应状态
|
|
1005
|
+
const checkedData = checkResponseStatus(response.data, response.status);
|
|
1006
|
+
// 处理响应
|
|
1007
|
+
return processResponse(checkedData, this.options);
|
|
1008
|
+
}
|
|
1009
|
+
catch (error) {
|
|
1010
|
+
return processError(error, this.options);
|
|
1011
|
+
}
|
|
763
1012
|
}
|
|
764
1013
|
/**
|
|
765
1014
|
* 获取时间同步服务实例
|
|
@@ -780,10 +1029,90 @@ class BeLinkHttp {
|
|
|
780
1029
|
/**
|
|
781
1030
|
* 获取 Axios 实例
|
|
782
1031
|
*
|
|
783
|
-
*
|
|
1032
|
+
* 仅在使用 axios 适配器时有效
|
|
1033
|
+
*
|
|
1034
|
+
* @returns Axios 实例,非 axios 适配器或未初始化时返回 null
|
|
784
1035
|
*/
|
|
785
1036
|
getAxiosInstance() {
|
|
786
|
-
|
|
1037
|
+
if (this.adapter instanceof AxiosAdapter) {
|
|
1038
|
+
return this.adapter.getAxiosInstance();
|
|
1039
|
+
}
|
|
1040
|
+
return null;
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* 获取当前适配器类型
|
|
1044
|
+
*
|
|
1045
|
+
* @returns 适配器类型,未初始化时返回 null
|
|
1046
|
+
*/
|
|
1047
|
+
getAdapterType() {
|
|
1048
|
+
if (!this.initialized || !this.options) {
|
|
1049
|
+
return null;
|
|
1050
|
+
}
|
|
1051
|
+
return this.options.adapter || 'axios';
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* 设置 Token
|
|
1055
|
+
*
|
|
1056
|
+
* 动态更新请求时使用的 Token,会覆盖 init 时传入的 getToken 返回值
|
|
1057
|
+
*
|
|
1058
|
+
* @param token - 新的 Token 值,传入 null 则清除
|
|
1059
|
+
*
|
|
1060
|
+
* @example
|
|
1061
|
+
* ```ts
|
|
1062
|
+
* // 登录后设置 Token
|
|
1063
|
+
* beLinkHttp.setToken('new-token-value');
|
|
1064
|
+
*
|
|
1065
|
+
* // 登出时清除 Token
|
|
1066
|
+
* beLinkHttp.setToken(null);
|
|
1067
|
+
* ```
|
|
1068
|
+
*/
|
|
1069
|
+
setToken(token) {
|
|
1070
|
+
this._token = token;
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* 设置 UserId
|
|
1074
|
+
*
|
|
1075
|
+
* 动态更新请求时使用的 UserId,会覆盖 init 时传入的 getUserId 返回值
|
|
1076
|
+
*
|
|
1077
|
+
* @param userId - 新的 UserId 值,传入 null 则清除
|
|
1078
|
+
*
|
|
1079
|
+
* @example
|
|
1080
|
+
* ```ts
|
|
1081
|
+
* // 登录后设置 UserId
|
|
1082
|
+
* beLinkHttp.setUserId('user-123');
|
|
1083
|
+
*
|
|
1084
|
+
* // 登出时清除 UserId
|
|
1085
|
+
* beLinkHttp.setUserId(null);
|
|
1086
|
+
* ```
|
|
1087
|
+
*/
|
|
1088
|
+
setUserId(userId) {
|
|
1089
|
+
this._userId = userId;
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* 获取当前 Token
|
|
1093
|
+
*
|
|
1094
|
+
* 优先返回通过 setToken 设置的值,否则调用 init 时传入的 getToken 函数
|
|
1095
|
+
*
|
|
1096
|
+
* @returns 当前 Token 值
|
|
1097
|
+
*/
|
|
1098
|
+
getToken() {
|
|
1099
|
+
if (this._token !== null) {
|
|
1100
|
+
return this._token;
|
|
1101
|
+
}
|
|
1102
|
+
return this.options?.getToken?.() ?? null;
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* 获取当前 UserId
|
|
1106
|
+
*
|
|
1107
|
+
* 优先返回通过 setUserId 设置的值,否则调用 init 时传入的 getUserId 函数
|
|
1108
|
+
*
|
|
1109
|
+
* @returns 当前 UserId 值
|
|
1110
|
+
*/
|
|
1111
|
+
getUserId() {
|
|
1112
|
+
if (this._userId !== null) {
|
|
1113
|
+
return this._userId;
|
|
1114
|
+
}
|
|
1115
|
+
return this.options?.getUserId?.() ?? null;
|
|
787
1116
|
}
|
|
788
1117
|
/**
|
|
789
1118
|
* 重置客户端
|
|
@@ -791,10 +1120,13 @@ class BeLinkHttp {
|
|
|
791
1120
|
* 清除所有配置和实例,需要重新调用 init() 初始化
|
|
792
1121
|
*/
|
|
793
1122
|
reset() {
|
|
794
|
-
this.
|
|
1123
|
+
this.adapter = null;
|
|
795
1124
|
this.timeSyncService = null;
|
|
796
1125
|
this.encryptionService = null;
|
|
1126
|
+
this.options = null;
|
|
797
1127
|
this.initialized = false;
|
|
1128
|
+
this._token = null;
|
|
1129
|
+
this._userId = null;
|
|
798
1130
|
}
|
|
799
1131
|
}
|
|
800
1132
|
/**
|
|
@@ -815,6 +1147,9 @@ class BeLinkHttp {
|
|
|
815
1147
|
*/
|
|
816
1148
|
const beLinkHttp = new BeLinkHttp();
|
|
817
1149
|
|
|
1150
|
+
exports.AxiosAdapter = AxiosAdapter;
|
|
818
1151
|
exports.BeLinkHttp = BeLinkHttp;
|
|
1152
|
+
exports.TaroAdapter = TaroAdapter;
|
|
819
1153
|
exports.beLinkHttp = beLinkHttp;
|
|
1154
|
+
exports.createTaroFetch = createTaroFetch;
|
|
820
1155
|
exports.default = beLinkHttp;
|