uniky 1.0.13 → 1.0.14

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.
@@ -0,0 +1,454 @@
1
+ // uniKy.ts
2
+
3
+ // 类型定义
4
+ export interface UniKyRequest {
5
+ url: string
6
+ method: string
7
+ headers: Record<string, string>
8
+ body?: any
9
+ timeout?: number
10
+ }
11
+
12
+ // 添加 ActiveHud 接口定义
13
+ export interface ActiveHud {
14
+ start(info?: any):void
15
+
16
+ end(success: boolean, message?: any):void
17
+ }
18
+
19
+ export interface UniKyOptions {
20
+ prefixUrl?: string
21
+ timeout?: number
22
+ headers?: Record<string, string>
23
+ retry?: number
24
+ method?: string
25
+ data?: any
26
+ searchParams?: Record<string, any> | URLSearchParams | string
27
+ hud?: ActiveHud // 添加 hud 属性
28
+ hooks?: {
29
+ beforeRequest?: Array<
30
+ (
31
+ request: UniKyRequest,
32
+ options: UniKyOptions,
33
+ ) => UniKyRequest | void | Promise<UniKyRequest | void>
34
+ >
35
+ afterResponse?: Array<
36
+ (
37
+ response: UniKyResponse,
38
+ request: UniKyRequest,
39
+ options: UniKyOptions,
40
+ ) => any | void | Promise<any | void>
41
+ >
42
+ }
43
+
44
+ [key: string]: any
45
+ }
46
+
47
+ export interface UniKyResponse<T = any> {
48
+ data: T
49
+ statusCode: number
50
+ header: Record<string, string>
51
+ cookies: string[]
52
+ ok: boolean
53
+ redirected: boolean
54
+ message?: string
55
+ url: string
56
+ }
57
+
58
+ export interface UniKyPromise<T = any> extends Promise<T> {
59
+ json<R = T>(): Promise<R>
60
+ }
61
+
62
+ export interface UniKyInstance {
63
+ <T = any>(url: string, options?: UniKyOptions): UniKyPromise<T>
64
+
65
+ get: <T = any>(url: string, options?: UniKyOptions) => UniKyPromise<T>
66
+ post: <T = any>(url: string, options?: UniKyOptions) => UniKyPromise<T>
67
+ put: <T = any>(url: string, options?: UniKyOptions) => UniKyPromise<T>
68
+ delete: <T = any>(url: string, options?: UniKyOptions) => UniKyPromise<T>
69
+ patch: <T = any>(url: string, options?: UniKyOptions) => UniKyPromise<T>
70
+ head: <T = any>(url: string, options?: UniKyOptions) => UniKyPromise<T>
71
+ options: <T = any>(url: string, options?: UniKyOptions) => UniKyPromise<T>
72
+ create: (defaultOptions: UniKyOptions) => UniKyInstance
73
+ extend: (options: UniKyOptions) => UniKyInstance
74
+ }
75
+
76
+ // 创建一个基础类实现所有方法
77
+ class UniKyBase {
78
+ protected defaultOptions: UniKyOptions
79
+
80
+ constructor(options: UniKyOptions = {}) {
81
+ this.defaultOptions = {
82
+ prefixUrl: '',
83
+ timeout: 60000,
84
+ headers: {},
85
+ retry: 0,
86
+ hooks: {
87
+ beforeRequest: [],
88
+ afterResponse: [],
89
+ },
90
+ ...options,
91
+ }
92
+ }
93
+
94
+ protected async request<T = any>(url: string, options: UniKyOptions = {}): Promise<T> {
95
+ const mergedOptions = this.mergeOptions(options)
96
+ const fullUrl = this.getFullUrl(url, mergedOptions)
97
+
98
+ // 如果有 hud,则调用 start 方法
99
+ if (mergedOptions.hud) {
100
+ mergedOptions.hud.start()
101
+ }
102
+
103
+ // 创建请求对象
104
+ let request: UniKyRequest = {
105
+ url: fullUrl,
106
+ method: (options.method || 'GET').toUpperCase(),
107
+ headers: mergedOptions.headers || {},
108
+ body: options.data,
109
+ timeout: mergedOptions.timeout,
110
+ }
111
+
112
+ // 执行请求前拦截器
113
+ if (mergedOptions.hooks?.beforeRequest?.length) {
114
+ for (const hook of mergedOptions.hooks.beforeRequest) {
115
+ const result = await hook(request, mergedOptions)
116
+ // 如果拦截器返回了新的请求对象,则使用它
117
+ if (result !== undefined && result !== null) {
118
+ request = result as UniKyRequest
119
+ }
120
+ // 如果拦截器没有返回值(void),则继续使用当前的请求对象
121
+ }
122
+ }
123
+
124
+ // 转换为 uni.request 需要的格式
125
+ const requestOptions: UniApp.RequestOptions = {
126
+ url: request.url,
127
+ method: request.method as
128
+ | 'GET'
129
+ | 'POST'
130
+ | 'PUT'
131
+ | 'DELETE'
132
+ | 'CONNECT'
133
+ | 'HEAD'
134
+ | 'OPTIONS'
135
+ | 'TRACE',
136
+ header: request.headers,
137
+ data: request.body,
138
+ timeout: request.timeout,
139
+ }
140
+
141
+ try {
142
+ let retries = mergedOptions.retry || 0
143
+ let response: any
144
+
145
+ while (true) {
146
+ try {
147
+ response = await this.makeRequest(requestOptions, request.url)
148
+ break
149
+ } catch (error) {
150
+ if (retries <= 0) {
151
+ // 如果是请求失败(网络错误等),直接使用错误对象
152
+ response = error
153
+ break
154
+ }
155
+ retries--
156
+ }
157
+ }
158
+
159
+ // 无论成功还是HTTP错误(如404),都执行响应后拦截器
160
+ if (mergedOptions.hooks?.afterResponse?.length) {
161
+ let processedResponse = response
162
+ for (const hook of mergedOptions.hooks.afterResponse) {
163
+ const result = await hook(processedResponse, request, mergedOptions)
164
+ // 如果拦截器返回了新的响应对象,则使用它
165
+ if (result !== undefined && result !== null) {
166
+ processedResponse = result
167
+ }
168
+ }
169
+
170
+ // 只在这里调用一次 hud.end
171
+ if (mergedOptions.hud) {
172
+ mergedOptions.hud.end(
173
+ processedResponse.ok,
174
+ !processedResponse.ok ? processedResponse : undefined,
175
+ )
176
+ }
177
+
178
+ // 如果是HTTP错误且没有被拦截器处理成功响应,则抛出
179
+ if (!processedResponse.ok) {
180
+ throw processedResponse
181
+ }
182
+
183
+ return processedResponse.data
184
+ }
185
+
186
+ // 只在这里调用一次 hud.end
187
+ if (mergedOptions.hud) {
188
+ mergedOptions.hud.end(response.ok, !response.ok ? response : undefined)
189
+ }
190
+
191
+ // 如果没有拦截器但有HTTP错误,抛出
192
+ if (!response.ok) {
193
+ throw response
194
+ }
195
+
196
+ return response.data
197
+ } catch (error:any) {
198
+ // 移除这里的 hud.end 调用,因为已经在上面调用过了
199
+ // 如果是网络错误等未捕获的异常,才在这里调用 hud.end
200
+ if (mergedOptions.hud && !error.statusCode) {
201
+ mergedOptions.hud.end(false, error)
202
+ }
203
+ throw error
204
+ }
205
+ }
206
+
207
+ protected makeRequest(
208
+ options: UniApp.RequestOptions,
209
+ originalUrl: string,
210
+ ): Promise<UniKyResponse> {
211
+ return new Promise((resolve, reject) => {
212
+ uni.request({
213
+ ...options,
214
+ success: (res) => {
215
+ const response: UniKyResponse = {
216
+ data: res.data,
217
+ statusCode: res.statusCode,
218
+ header: res.header,
219
+ cookies: res.cookies || [],
220
+ ok: res.statusCode >= 200 && res.statusCode < 300,
221
+ redirected: res.statusCode === 301 || res.statusCode === 302,
222
+ url: originalUrl,
223
+ }
224
+
225
+ // 处理非2xx状态码
226
+ if (response.ok) {
227
+ resolve(response)
228
+ } else {
229
+ reject(response)
230
+ }
231
+ },
232
+ fail: (err) => {
233
+ reject({
234
+ ...err,
235
+ ok: false,
236
+ statusCode: 0,
237
+ header: {},
238
+ cookies: [],
239
+ redirected: false,
240
+ url: originalUrl,
241
+ data: null,
242
+ })
243
+ },
244
+ })
245
+ })
246
+ }
247
+
248
+ protected mergeOptions(options: UniKyOptions): UniKyOptions {
249
+ // 创建新的 hooks 对象,确保不修改原始对象
250
+ const mergedHooks = {
251
+ beforeRequest: [...(this.defaultOptions.hooks?.beforeRequest || [])],
252
+ afterResponse: [...(this.defaultOptions.hooks?.afterResponse || [])],
253
+ }
254
+
255
+ // 添加传入的 hooks
256
+ if (options.hooks?.beforeRequest) {
257
+ if (Array.isArray(options.hooks.beforeRequest)) {
258
+ mergedHooks.beforeRequest.push(...options.hooks.beforeRequest)
259
+ } else {
260
+ // 如果不是数组,转换为数组
261
+ mergedHooks.beforeRequest.push(options.hooks.beforeRequest as any)
262
+ }
263
+ }
264
+
265
+ if (options.hooks?.afterResponse) {
266
+ if (Array.isArray(options.hooks.afterResponse)) {
267
+ mergedHooks.afterResponse.push(...options.hooks.afterResponse)
268
+ } else {
269
+ // 如果不是数组,转换为数组
270
+ mergedHooks.afterResponse.push(options.hooks.afterResponse as any)
271
+ }
272
+ }
273
+
274
+ return {
275
+ ...this.defaultOptions,
276
+ ...options,
277
+ headers: {
278
+ ...this.defaultOptions.headers,
279
+ ...options.headers,
280
+ },
281
+ hooks: mergedHooks,
282
+ }
283
+ }
284
+
285
+ protected addSearchParams(
286
+ url: string,
287
+ searchParams?: Record<string, any> | URLSearchParams | string,
288
+ ): string {
289
+ if (!searchParams) {
290
+ return url
291
+ }
292
+
293
+ // 准备查询字符串
294
+ let queryString = ''
295
+
296
+ if (typeof searchParams === 'string') {
297
+ // 如果是字符串,直接使用
298
+ queryString = searchParams.startsWith('?') ? searchParams.substring(1) : searchParams
299
+ } else if (typeof URLSearchParams !== 'undefined' && searchParams instanceof URLSearchParams) {
300
+ // 如果是 URLSearchParams 实例,转为字符串
301
+ queryString = searchParams.toString()
302
+ } else if (searchParams && typeof searchParams === 'object') {
303
+ // 如果是对象,手动构建查询字符串
304
+ const params = []
305
+ for (const [key, value] of Object.entries(searchParams)) {
306
+ if (value !== undefined && value !== null) {
307
+ // @ts-ignore
308
+ params.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
309
+ }
310
+ }
311
+ queryString = params.join('&')
312
+ }
313
+
314
+ // 添加到 URL
315
+ const hasQueryString = url.includes('?')
316
+ if (queryString) {
317
+ return url + (hasQueryString ? '&' : '?') + queryString
318
+ }
319
+
320
+ return url
321
+ }
322
+
323
+ protected getFullUrl(url: string, options: UniKyOptions): string {
324
+ const prefixUrl = options.prefixUrl ? options.prefixUrl.replace(/\/$/, '') : ''
325
+
326
+ // 首先判断是否是完整URL
327
+ if (url.startsWith('http://') || url.startsWith('https://')) {
328
+ // 对完整URL添加查询参数
329
+ return this.addSearchParams(url, options.searchParams)
330
+ }
331
+
332
+ // 处理相对路径
333
+ const normalizedUrl = url.startsWith('/') ? url : `/${url}`
334
+ const fullUrl = `${prefixUrl}${normalizedUrl}`
335
+
336
+ // 添加查询参数
337
+ return this.addSearchParams(fullUrl, options.searchParams)
338
+ }
339
+
340
+ // 创建具有 json 方法的 Promise
341
+ protected createUniKyPromise<T>(promise: Promise<T>): UniKyPromise<T> {
342
+ const uniKyPromise = promise as UniKyPromise<T>
343
+
344
+ uniKyPromise.json = function <R = T>() {
345
+ return this.then((data) => {
346
+ if (typeof data === 'string') {
347
+ try {
348
+ return JSON.parse(data)
349
+ } catch (e) {
350
+ return data as unknown as R
351
+ }
352
+ }
353
+ return data as unknown as R
354
+ })
355
+ }
356
+
357
+ return uniKyPromise
358
+ }
359
+
360
+ get<T = any>(url: string, options: UniKyOptions = {}): UniKyPromise<T> {
361
+ return this.createUniKyPromise(this.request<T>(url, { ...options, method: 'GET' }))
362
+ }
363
+
364
+ post<T = any>(url: string, options: UniKyOptions = {}): UniKyPromise<T> {
365
+ return this.createUniKyPromise(this.request<T>(url, { ...options, method: 'POST' }))
366
+ }
367
+
368
+ put<T = any>(url: string, options: UniKyOptions = {}): UniKyPromise<T> {
369
+ return this.createUniKyPromise(this.request<T>(url, { ...options, method: 'PUT' }))
370
+ }
371
+
372
+ delete<T = any>(url: string, options: UniKyOptions = {}): UniKyPromise<T> {
373
+ return this.createUniKyPromise(this.request<T>(url, { ...options, method: 'DELETE' }))
374
+ }
375
+
376
+ patch<T = any>(url: string, options: UniKyOptions = {}): UniKyPromise<T> {
377
+ return this.createUniKyPromise(this.request<T>(url, { ...options, method: 'PATCH' }))
378
+ }
379
+
380
+ head<T = any>(url: string, options: UniKyOptions = {}): UniKyPromise<T> {
381
+ return this.createUniKyPromise(this.request<T>(url, { ...options, method: 'HEAD' }))
382
+ }
383
+
384
+ options<T = any>(url: string, options: UniKyOptions = {}): UniKyPromise<T> {
385
+ return this.createUniKyPromise(this.request<T>(url, { ...options, method: 'OPTIONS' }))
386
+ }
387
+ }
388
+
389
+ // 使用函数工厂模式创建符合 UniKyInstance 接口的实例
390
+ function createUniKy(defaultOptions: UniKyOptions = {}): UniKyInstance {
391
+ const base = new UniKyBase(defaultOptions)
392
+
393
+ // 创建主函数
394
+ const uniKyFunction = <T = any>(url: string, options: UniKyOptions = {}): UniKyPromise<T> => {
395
+ return base['createUniKyPromise'](base['request']<T>(url, options))
396
+ }
397
+
398
+ // 添加所有方法
399
+ uniKyFunction.get = base.get.bind(base)
400
+ uniKyFunction.post = base.post.bind(base)
401
+ uniKyFunction.put = base.put.bind(base)
402
+ uniKyFunction.delete = base.delete.bind(base)
403
+ uniKyFunction.patch = base.patch.bind(base)
404
+ uniKyFunction.head = base.head.bind(base)
405
+ uniKyFunction.options = base.options.bind(base)
406
+
407
+ // 添加 create 方法
408
+ uniKyFunction.create = (options: UniKyOptions): UniKyInstance => {
409
+ // 深度合并 hooks
410
+ const mergedHooks = {
411
+ beforeRequest: [...(defaultOptions.hooks?.beforeRequest || [])],
412
+ afterResponse: [...(defaultOptions.hooks?.afterResponse || [])],
413
+ }
414
+
415
+ // 添加传入的 hooks
416
+ if (options.hooks?.beforeRequest) {
417
+ if (Array.isArray(options.hooks.beforeRequest)) {
418
+ mergedHooks.beforeRequest.push(...options.hooks.beforeRequest)
419
+ } else {
420
+ // 如果不是数组,转换为数组
421
+ mergedHooks.beforeRequest.push(options.hooks.beforeRequest as any)
422
+ }
423
+ }
424
+
425
+ if (options.hooks?.afterResponse) {
426
+ if (Array.isArray(options.hooks.afterResponse)) {
427
+ mergedHooks.afterResponse.push(...options.hooks.afterResponse)
428
+ } else {
429
+ // 如果不是数组,转换为数组
430
+ mergedHooks.afterResponse.push(options.hooks.afterResponse as any)
431
+ }
432
+ }
433
+
434
+ return createUniKy({
435
+ ...defaultOptions,
436
+ ...options,
437
+ hooks: mergedHooks,
438
+ headers: {
439
+ ...defaultOptions.headers,
440
+ ...options.headers,
441
+ },
442
+ })
443
+ }
444
+
445
+ // 添加 extend 方法
446
+ uniKyFunction.extend = (options: UniKyOptions): UniKyInstance => {
447
+ return uniKyFunction.create(options)
448
+ }
449
+
450
+ return uniKyFunction
451
+ }
452
+
453
+ // 默认导出实例
454
+ export const uniKy = createUniKy()
@@ -1,4 +1,3 @@
1
1
  // created by zhuxietong on 2026-01-30 16:37
2
2
  export * from './hook/index.js';
3
3
  export * from './http/index.js';
4
- //# sourceMappingURL=index.js.map