diff --git a/src/hooks/useRequest.ts b/src/hooks/useRequest.ts index 2d156cc..7aa7bc6 100644 --- a/src/hooks/useRequest.ts +++ b/src/hooks/useRequest.ts @@ -1,4 +1,5 @@ import type { Ref } from 'vue' +import type { HttpRequestResult } from '@/http/types' import { ref } from 'vue' interface IUseRequestOptions { @@ -13,6 +14,7 @@ interface IUseRequestReturn { error: Ref data: Ref run: (args?: P) => Promise + cancel: () => void } /** @@ -24,15 +26,19 @@ interface IUseRequestReturn { * @returns 返回一个对象{loading, error, data, run},包含请求的加载状态、错误信息、响应数据和手动触发请求的函数。 */ export default function useRequest( - func: (args?: P) => Promise, + func: (args?: P) => HttpRequestResult, options: IUseRequestOptions = { immediate: false }, ): IUseRequestReturn { const loading = ref(false) - const error = ref(false) + const error = ref(false) const data = ref(options.initialData) as Ref + let requestTask: UniApp.RequestTask | undefined + const run = async (args?: P) => { loading.value = true - return func(args) + const { promise, requestTask: task } = func(args) + requestTask = task // Store the requestTask + return promise .then((res) => { data.value = res error.value = false @@ -47,8 +53,16 @@ export default function useRequest( }) } + const cancel = () => { + if (requestTask) { + requestTask.abort() + loading.value = false // Reset loading state on cancel + error.value = new Error('Request cancelled') // Set a specific error for cancellation + } + } + if (options.immediate) { (run as (args?: P) => Promise)({} as P) } - return { loading, error, data, run } + return { loading, error, data, run, cancel } } diff --git a/src/http/http.ts b/src/http/http.ts index 7720a8d..c5e693d 100644 --- a/src/http/http.ts +++ b/src/http/http.ts @@ -8,12 +8,12 @@ import { ResultEnum } from './tools/enum' // 刷新 token 状态管理 let refreshing = false // 防止重复刷新 token 标识 -let taskQueue: (() => void)[] = [] // 刷新 token 请求队列 +let taskQueue: { resolve: (value: any) => void, reject: (reason?: any) => void, options: CustomRequestOptions }[] = [] as { resolve: (value: any) => void, reject: (reason?: any) => void, options: CustomRequestOptions }[] // 刷新 token 请求队列 export function http(options: CustomRequestOptions) { - // 1. 返回 Promise 对象 - return new Promise((resolve, reject) => { - uni.request({ + let requestTask: UniApp.RequestTask | undefined + const promise = new Promise((resolve, reject) => { + requestTask = uni.request({ ...options, dataType: 'json', // #ifndef MP-WEIXIN @@ -44,9 +44,7 @@ export function http(options: CustomRequestOptions) { const { refreshToken } = tokenStore.tokenInfo as IDoubleTokenRes || {} // token 失效的,且有刷新 token 的,才放到请求队列里 if ((res.statusCode === 401 || resData.code === 401) && refreshToken) { - taskQueue.push(() => { - resolve(http(options)) - }) + taskQueue.push({ resolve, reject, options }) } // 如果有 refreshToken 且未在刷新中,发起刷新 token 请求 if ((res.statusCode === 401 || resData.code === 401) && refreshToken && !refreshing) { @@ -65,7 +63,9 @@ export function http(options: CustomRequestOptions) { }) }) // 将任务队列的所有任务重新请求 - taskQueue.forEach(task => task()) + taskQueue.forEach((task) => { + http(task.options).promise.then(task.resolve, task.reject) + }) } catch (refreshErr) { console.error('刷新 token 失败:', refreshErr) @@ -112,6 +112,7 @@ export function http(options: CustomRequestOptions) { }, }) }) + return { promise, requestTask: requestTask! } } /** diff --git a/src/http/types.ts b/src/http/types.ts index 25cf472..a622e0b 100644 --- a/src/http/types.ts +++ b/src/http/types.ts @@ -7,6 +7,11 @@ export type CustomRequestOptions = UniApp.RequestOptions & { hideErrorToast?: boolean } & IUniUploadFileOptions // 添加uni.uploadFile参数类型 +export interface HttpRequestResult { + promise: Promise + requestTask: UniApp.RequestTask +} + // 通用响应格式 export interface IResponse { code: number | string diff --git a/src/pages/about/components/request.vue b/src/pages/about/components/request.vue index ac1b7a3..2196a2a 100644 --- a/src/pages/about/components/request.vue +++ b/src/pages/about/components/request.vue @@ -8,10 +8,14 @@ import { getFooAPI } from '@/api/foo' // } const initialData = undefined -const { loading, error, data, run } = useRequest(() => getFooAPI('菲鸽'), { +const { loading, error, data, run, cancel } = useRequest(() => getFooAPI('菲鸽'), { immediate: true, initialData, }) +function reqFooAPI() { + run() + cancel() +} function reset() { data.value = initialData @@ -31,17 +35,31 @@ function reset() { + + loading... - - 请求数据如下 + + 错误: {{ error.message }} - - {{ JSON.stringify(data) }} + + 错误: 未知错误 + + + + 请求数据如下 + + + {{ JSON.stringify(data) }} +