新增
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
import { RequestTask } from './type'
|
||||
|
||||
const cancelerMap = new Map<string, RequestTask>()
|
||||
|
||||
export class RequestCancel {
|
||||
private static instance?: RequestCancel
|
||||
|
||||
static createInstance() {
|
||||
return this.instance ?? (this.instance = new RequestCancel())
|
||||
}
|
||||
add(url: string, requestTask: RequestTask) {
|
||||
this.remove(url)
|
||||
if (cancelerMap.has(url)) {
|
||||
cancelerMap.delete(url)
|
||||
}
|
||||
cancelerMap.set(url, requestTask)
|
||||
}
|
||||
remove(url: string) {
|
||||
if (cancelerMap.has(url)) {
|
||||
const requestTask = cancelerMap.get(url)
|
||||
requestTask && requestTask.abort()
|
||||
cancelerMap.delete(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const requestCancel = RequestCancel.createInstance()
|
||||
|
||||
export default requestCancel
|
||||
@@ -0,0 +1,140 @@
|
||||
import { merge } from 'lodash-es'
|
||||
import { isFunction } from '@vue/shared'
|
||||
import { HttpRequestOptions, RequestConfig, RequestOptions, UploadFileOption } from './type'
|
||||
import { RequestErrMsgEnum, RequestMethodsEnum } from '@/enums/requestEnums'
|
||||
import requestCancel from './cancel'
|
||||
|
||||
export default class HttpRequest {
|
||||
private readonly options: HttpRequestOptions
|
||||
constructor(options: HttpRequestOptions) {
|
||||
this.options = options
|
||||
}
|
||||
/**
|
||||
* @description 重新请求
|
||||
*/
|
||||
retryRequest(options: RequestOptions, config: RequestConfig) {
|
||||
const { retryCount, retryTimeout } = config
|
||||
if (!retryCount || options.method?.toUpperCase() == RequestMethodsEnum.POST) {
|
||||
return Promise.reject()
|
||||
}
|
||||
uni.showLoading({ title: '加载中...' })
|
||||
config.hasRetryCount = config.hasRetryCount ?? 0
|
||||
if (config.hasRetryCount >= retryCount) {
|
||||
return Promise.reject()
|
||||
}
|
||||
config.hasRetryCount++
|
||||
config.requestHooks.requestInterceptorsHook = (options) => options
|
||||
return new Promise((resolve) => setTimeout(resolve, retryTimeout))
|
||||
.then(() => this.request(options, config))
|
||||
.finally(() => uni.hideLoading())
|
||||
}
|
||||
/**
|
||||
* @description get请求
|
||||
*/
|
||||
get<T = any>(options: RequestOptions, config?: Partial<RequestConfig>): Promise<T> {
|
||||
return this.request({ ...options, method: RequestMethodsEnum.GET }, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description post请求
|
||||
*/
|
||||
post<T = any>(options: RequestOptions, config?: Partial<RequestConfig>): Promise<T> {
|
||||
return this.request({ ...options, method: RequestMethodsEnum.POST }, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 上传图片
|
||||
*/
|
||||
uploadFile(options: UploadFileOption, config?: Partial<RequestConfig>) {
|
||||
let mergeOptions: RequestOptions = merge({}, this.options.requestOptions, options)
|
||||
const mergeConfig: RequestConfig = merge({}, this.options, config)
|
||||
const { requestInterceptorsHook, responseInterceptorsHook, responseInterceptorsCatchHook } =
|
||||
mergeConfig.requestHooks || {}
|
||||
if (requestInterceptorsHook && isFunction(requestInterceptorsHook)) {
|
||||
mergeOptions = requestInterceptorsHook(mergeOptions, mergeConfig)
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
...mergeOptions,
|
||||
success: async (response) => {
|
||||
if (response.statusCode == 200) {
|
||||
response.data = JSON.parse(response.data)
|
||||
if (responseInterceptorsHook && isFunction(responseInterceptorsHook)) {
|
||||
try {
|
||||
response = await responseInterceptorsHook(response, mergeConfig)
|
||||
resolve(response)
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
}
|
||||
return
|
||||
}
|
||||
resolve(response)
|
||||
}
|
||||
},
|
||||
fail: async (err) => {
|
||||
if (
|
||||
responseInterceptorsCatchHook &&
|
||||
isFunction(responseInterceptorsCatchHook)
|
||||
) {
|
||||
reject(await responseInterceptorsCatchHook(mergeOptions, err))
|
||||
return
|
||||
}
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @description 请求函数
|
||||
*/
|
||||
async request(options: RequestOptions, config?: Partial<RequestConfig>): Promise<any> {
|
||||
let mergeOptions: RequestOptions = merge({}, this.options.requestOptions, options)
|
||||
const mergeConfig: RequestConfig = merge({}, this.options, config)
|
||||
const { requestInterceptorsHook, responseInterceptorsHook, responseInterceptorsCatchHook } =
|
||||
mergeConfig.requestHooks || {}
|
||||
if (requestInterceptorsHook && isFunction(requestInterceptorsHook)) {
|
||||
mergeOptions = requestInterceptorsHook(mergeOptions, mergeConfig)
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const requestTask = uni.request({
|
||||
...mergeOptions,
|
||||
async success(response) {
|
||||
if (responseInterceptorsHook && isFunction(responseInterceptorsHook)) {
|
||||
try {
|
||||
response = await responseInterceptorsHook(response, mergeConfig)
|
||||
resolve(response)
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
}
|
||||
return
|
||||
}
|
||||
resolve(response)
|
||||
},
|
||||
fail: async (err) => {
|
||||
if (err.errMsg == RequestErrMsgEnum.TIMEOUT) {
|
||||
this.retryRequest(mergeOptions, mergeConfig)
|
||||
.then((res) => resolve(res))
|
||||
.catch((err) => reject(err))
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
responseInterceptorsCatchHook &&
|
||||
isFunction(responseInterceptorsCatchHook)
|
||||
) {
|
||||
reject(await responseInterceptorsCatchHook(mergeOptions, err))
|
||||
return
|
||||
}
|
||||
reject(err)
|
||||
},
|
||||
complete(err) {
|
||||
if (err.errMsg !== RequestErrMsgEnum.ABORT) {
|
||||
requestCancel.remove(options.url)
|
||||
}
|
||||
}
|
||||
})
|
||||
const { ignoreCancel } = mergeConfig
|
||||
!ignoreCancel && requestCancel.add(options.url, requestTask)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import HttpRequest from "./http";
|
||||
import { merge } from "lodash-es";
|
||||
import { HttpRequestOptions, RequestHooks } from "./type";
|
||||
import { getToken } from "../auth";
|
||||
import { RequestCodeEnum, RequestMethodsEnum } from "@/enums/requestEnums";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import appConfig from "@/config";
|
||||
import { getClient } from "../client";
|
||||
|
||||
const requestHooks: RequestHooks = {
|
||||
requestInterceptorsHook(options, config) {
|
||||
const { urlPrefix, baseUrl, withToken, isAuth } = config;
|
||||
options.header = options.header ?? {};
|
||||
if (urlPrefix) {
|
||||
options.url = `${urlPrefix}${options.url}`;
|
||||
}
|
||||
if (baseUrl) {
|
||||
options.url = `${baseUrl}${options.url}`;
|
||||
}
|
||||
const token = getToken();
|
||||
// 添加token
|
||||
if (withToken && !options.header.token) {
|
||||
options.header.token = token;
|
||||
}
|
||||
options.header.version = appConfig.version;
|
||||
// options.header.terminal = getClient();
|
||||
return options;
|
||||
},
|
||||
async responseInterceptorsHook(response, config) {
|
||||
const { isTransformResponse, isReturnDefaultResponse, isAuth } = config;
|
||||
|
||||
//返回默认响应,当需要获取响应头及其他数据时可使用
|
||||
if (isReturnDefaultResponse) {
|
||||
return response;
|
||||
}
|
||||
// 是否需要对数据进行处理
|
||||
if (!isTransformResponse) {
|
||||
return response.data;
|
||||
}
|
||||
const { logout } = useUserStore();
|
||||
const { code, data, msg, show } = response.data as any;
|
||||
switch (code) {
|
||||
case RequestCodeEnum.SUCCESS:
|
||||
msg && show && uni.$u.toast(msg);
|
||||
return data;
|
||||
case RequestCodeEnum.FAILED:
|
||||
uni.$u.toast(msg);
|
||||
return Promise.reject(msg);
|
||||
|
||||
case RequestCodeEnum.TOKEN_INVALID:
|
||||
logout();
|
||||
if (isAuth && !getToken()) {
|
||||
uni.navigateTo({
|
||||
url: "/pages/login/login",
|
||||
});
|
||||
}
|
||||
return Promise.reject(msg);
|
||||
|
||||
default:
|
||||
return data;
|
||||
}
|
||||
},
|
||||
async responseInterceptorsCatchHook(options, error) {
|
||||
if (options.method?.toUpperCase() == RequestMethodsEnum.POST) {
|
||||
uni.$u.toast("请求失败,请重试");
|
||||
}
|
||||
return Promise.reject(error);
|
||||
},
|
||||
};
|
||||
|
||||
const defaultOptions: HttpRequestOptions = {
|
||||
requestOptions: {
|
||||
timeout: appConfig.timeout,
|
||||
},
|
||||
baseUrl: appConfig.baseUrl,
|
||||
//是否返回默认的响应
|
||||
isReturnDefaultResponse: false,
|
||||
// 需要对返回数据进行处理
|
||||
isTransformResponse: true,
|
||||
// 接口拼接地址
|
||||
urlPrefix: "api",
|
||||
// 忽略重复请求
|
||||
ignoreCancel: false,
|
||||
// 是否携带token
|
||||
withToken: true,
|
||||
isAuth: false,
|
||||
retryCount: 2,
|
||||
retryTimeout: 1000,
|
||||
requestHooks: requestHooks,
|
||||
};
|
||||
|
||||
function createRequest(opt?: HttpRequestOptions) {
|
||||
return new HttpRequest(
|
||||
// 深度合并
|
||||
merge(defaultOptions, opt || {})
|
||||
);
|
||||
}
|
||||
const request = createRequest();
|
||||
export default request;
|
||||
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
export type RequestOptions = UniApp.RequestOptions
|
||||
export type ResponseResult =
|
||||
| UniApp.RequestSuccessCallbackResult
|
||||
| UniApp.UploadFileSuccessCallbackResult
|
||||
export type RequestOptionsResponseError = UniApp.GeneralCallbackResult
|
||||
export type RequestTask = UniApp.RequestTask
|
||||
export type UploadFileOption = UniApp.UploadFileOption
|
||||
export interface HttpRequestOptions extends RequestConfig {
|
||||
requestOptions: Partial<RequestOptions>
|
||||
}
|
||||
|
||||
export interface RequestConfig {
|
||||
baseUrl: string
|
||||
requestHooks: RequestHooks
|
||||
isReturnDefaultResponse: boolean
|
||||
isTransformResponse: boolean
|
||||
urlPrefix: string
|
||||
ignoreCancel: boolean
|
||||
withToken: boolean
|
||||
isAuth: boolean
|
||||
retryCount: number
|
||||
retryTimeout: number
|
||||
hasRetryCount?: number
|
||||
}
|
||||
|
||||
export interface RequestHooks {
|
||||
requestInterceptorsHook?(options: RequestOptions, config: RequestConfig): RequestOptions
|
||||
responseInterceptorsHook?(response: ResponseResult, config: RequestConfig): any
|
||||
responseInterceptorsCatchHook?(options: RequestOptions, error: any): any
|
||||
}
|
||||
Reference in New Issue
Block a user