-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(https): ♻️ change umi-request to axios
- Loading branch information
G
committed
May 10, 2024
1 parent
e695a87
commit c35350d
Showing
12 changed files
with
622 additions
and
115 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from "./modules/format-number"; | ||
export * from "./modules/is"; | ||
export * from "./modules/storage"; | ||
export * from "./modules/tree"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
export { isFunction } from "lodash-es"; | ||
const { toString } = Object.prototype; | ||
/** | ||
* 检查给定的值是否为指定的类型。 | ||
* | ||
* @param {unknown} val - 要检查的值。 | ||
* @param {string} type - 要检查的类型。 | ||
* @return {boolean} 如果值是指定类型,则返回true,否则返回false。 | ||
*/ | ||
export function is(val: unknown, type: string) { | ||
return toString.call(val) === `[object ${type}]`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
import type { AxiosRequestConfig, AxiosInstance, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios'; | ||
import type { RequestOptions, Result, UploadFileParams } from '../types/axios'; | ||
import type { CreateAxiosOptions } from './axiosTransform'; | ||
import axios from 'axios'; | ||
import qs from 'qs'; | ||
import { AxiosCanceler } from './axiosCancel'; | ||
import { isFunction } from '@gbeata/utils'; | ||
import { cloneDeep } from 'lodash-es'; | ||
import { ContentTypeEnum, RequestEnum } from '../enums/httpEnum'; | ||
|
||
export * from './axiosTransform'; | ||
|
||
/** | ||
* @description: axios module | ||
*/ | ||
export class GAxios { | ||
private axiosInstance: AxiosInstance; | ||
private readonly options: CreateAxiosOptions; | ||
|
||
constructor(options: CreateAxiosOptions) { | ||
this.options = options; | ||
this.axiosInstance = axios.create(options); | ||
this.setupInterceptors(); | ||
} | ||
|
||
/** | ||
* @description: Create axios instance | ||
*/ | ||
private createAxios(config: CreateAxiosOptions): void { | ||
this.axiosInstance = axios.create(config); | ||
} | ||
|
||
private getTransform() { | ||
const { transform } = this.options; | ||
return transform; | ||
} | ||
|
||
getAxios(): AxiosInstance { | ||
return this.axiosInstance; | ||
} | ||
|
||
/** | ||
* @description: Reconfigure axios | ||
*/ | ||
configAxios(config: CreateAxiosOptions) { | ||
if (!this.axiosInstance) { | ||
return; | ||
} | ||
this.createAxios(config); | ||
} | ||
|
||
/** | ||
* @description: Set general header | ||
*/ | ||
setHeader(headers: any): void { | ||
if (!this.axiosInstance) { | ||
return; | ||
} | ||
Object.assign(this.axiosInstance.defaults.headers, headers); | ||
} | ||
|
||
/** | ||
* @description: Interceptor configuration 拦截器配置 | ||
*/ | ||
private setupInterceptors() { | ||
// const transform = this.getTransform(); | ||
const { | ||
axiosInstance, | ||
options: { transform }, | ||
} = this; | ||
if (!transform) { | ||
return; | ||
} | ||
const { requestInterceptors, requestInterceptorsCatch, responseInterceptors, responseInterceptorsCatch } = | ||
transform; | ||
|
||
const axiosCanceler = new AxiosCanceler(); | ||
|
||
// Request interceptor configuration processing | ||
this.axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => { | ||
// If cancel repeat request is turned on, then cancel repeat request is prohibited | ||
const requestOptions = (config as unknown as any).requestOptions ?? this.options.requestOptions; | ||
const ignoreCancelToken = requestOptions?.ignoreCancelToken ?? true; | ||
|
||
!ignoreCancelToken && axiosCanceler.addPending(config); | ||
|
||
if (requestInterceptors && isFunction(requestInterceptors)) { | ||
config = requestInterceptors(config, this.options); | ||
} | ||
return config; | ||
}, undefined); | ||
|
||
// Request interceptor error capture | ||
requestInterceptorsCatch && | ||
isFunction(requestInterceptorsCatch) && | ||
this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch); | ||
|
||
// Response result interceptor processing | ||
this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => { | ||
res && axiosCanceler.removePending(res.config); | ||
if (responseInterceptors && isFunction(responseInterceptors)) { | ||
res = responseInterceptors(res); | ||
} | ||
return res; | ||
}, undefined); | ||
|
||
// Response result interceptor error capture | ||
responseInterceptorsCatch && | ||
isFunction(responseInterceptorsCatch) && | ||
this.axiosInstance.interceptors.response.use(undefined, (error) => { | ||
return responseInterceptorsCatch(axiosInstance, error); | ||
}); | ||
} | ||
|
||
/** | ||
* @description: File Upload | ||
*/ | ||
uploadFile<T = any>(config: AxiosRequestConfig, params: UploadFileParams) { | ||
const formData = new window.FormData(); | ||
const customFilename = params.name || 'file'; | ||
|
||
if (params.filename) { | ||
formData.append(customFilename, params.file, params.filename); | ||
} else { | ||
formData.append(customFilename, params.file); | ||
} | ||
|
||
if (params.data) { | ||
Object.keys(params.data).forEach((key) => { | ||
const value = params.data![key]; | ||
if (Array.isArray(value)) { | ||
value.forEach((item) => { | ||
formData.append(`${key}[]`, item); | ||
}); | ||
return; | ||
} | ||
|
||
formData.append(key, params.data![key]); | ||
}); | ||
} | ||
|
||
return this.axiosInstance.request<T>({ | ||
...config, | ||
method: 'POST', | ||
data: formData, | ||
headers: { | ||
'Content-type': ContentTypeEnum.FORM_DATA, | ||
// @ts-ignore | ||
ignoreCancelToken: true, | ||
}, | ||
}); | ||
} | ||
|
||
// support form-data | ||
supportFormData(config: AxiosRequestConfig) { | ||
const headers = config.headers || this.options.headers; | ||
const contentType = headers?.['Content-Type'] || headers?.['content-type']; | ||
|
||
if ( | ||
contentType !== ContentTypeEnum.FORM_URLENCODED || | ||
!Reflect.has(config, 'data') || | ||
config.method?.toUpperCase() === RequestEnum.GET | ||
) { | ||
return config; | ||
} | ||
|
||
return { | ||
...config, | ||
data: qs.stringify(config.data, { arrayFormat: 'brackets' }), | ||
}; | ||
} | ||
|
||
get<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> { | ||
return this.request({ ...config, method: 'GET' }, options); | ||
} | ||
|
||
post<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> { | ||
return this.request({ ...config, method: 'POST' }, options); | ||
} | ||
|
||
put<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> { | ||
return this.request({ ...config, method: 'PUT' }, options); | ||
} | ||
|
||
delete<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> { | ||
return this.request({ ...config, method: 'DELETE' }, options); | ||
} | ||
|
||
request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> { | ||
let conf: CreateAxiosOptions = cloneDeep(config); | ||
// cancelToken 如果被深拷贝,会导致最外层无法使用cancel方法来取消请求 | ||
if (config.cancelToken) { | ||
conf.cancelToken = config.cancelToken; | ||
} | ||
|
||
if (config.signal) { | ||
conf.signal = config.signal; | ||
} | ||
|
||
const transform = this.getTransform(); | ||
|
||
const { requestOptions } = this.options; | ||
|
||
const opt: RequestOptions = Object.assign({}, requestOptions, options); | ||
|
||
const { beforeRequestHook, requestCatchHook, transformResponseHook } = transform || {}; | ||
if (beforeRequestHook && isFunction(beforeRequestHook)) { | ||
conf = beforeRequestHook(conf, opt); | ||
} | ||
conf.requestOptions = opt; | ||
|
||
conf = this.supportFormData(conf); | ||
|
||
return new Promise((resolve, reject) => { | ||
this.axiosInstance | ||
.request<any, AxiosResponse<Result>>(conf) | ||
.then((res: AxiosResponse<Result>) => { | ||
if (transformResponseHook && isFunction(transformResponseHook)) { | ||
try { | ||
const ret = transformResponseHook(res, opt); | ||
resolve(ret); | ||
} catch (err) { | ||
reject(err || new Error('request error!')); | ||
} | ||
return; | ||
} | ||
resolve(res as unknown as Promise<T>); | ||
}) | ||
.catch((e: Error | AxiosError) => { | ||
if (requestCatchHook && isFunction(requestCatchHook)) { | ||
reject(requestCatchHook(e, opt)); | ||
return; | ||
} | ||
if (axios.isAxiosError(e)) { | ||
// rewrite error message from axios in here | ||
} | ||
reject(e); | ||
}); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// import type { AxiosRequestConfig } from 'axios'; | ||
|
||
import { AxiosRequestConfig } from 'axios'; | ||
|
||
export class AxiosCanceler { | ||
public addPending(config: AxiosRequestConfig): void {} | ||
|
||
public removePending(config: AxiosRequestConfig): void {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import type { AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig, AxiosInstance } from 'axios'; | ||
import { RequestOptions, Result } from '../types/axios'; | ||
|
||
export interface CreateAxiosOptions extends AxiosRequestConfig { | ||
authenticationScheme?: string; | ||
transform?: AxiosTransform; | ||
requestOptions?: RequestOptions; | ||
} | ||
|
||
export abstract class AxiosTransform { | ||
/** | ||
* @description: 请求前处理配置 | ||
*/ | ||
beforeRequestHook?: (config: AxiosRequestConfig, options: RequestOptions) => AxiosRequestConfig; | ||
|
||
/** | ||
* @description: 请求拦截器错误处理 | ||
*/ | ||
requestInterceptorsCatch?: (error: any) => void; | ||
|
||
/** | ||
* @description: 响应拦截器处理 | ||
*/ | ||
responseInterceptors?: (res: AxiosResponse<any>) => AxiosResponse<any>; | ||
|
||
/** | ||
* @description: 请求失败处理 | ||
*/ | ||
requestCatchHook?: (e: Error, options: RequestOptions) => Promise<any>; | ||
|
||
/** | ||
* @description: 处理响应数据 | ||
*/ | ||
transformResponseHook?: (res: AxiosResponse<Result>, options: RequestOptions) => any; | ||
/** | ||
* @description: 请求之前的拦截器 | ||
*/ | ||
requestInterceptors?: (config: InternalAxiosRequestConfig, options: CreateAxiosOptions) => InternalAxiosRequestConfig; | ||
/** | ||
* @description: 请求之后的拦截器错误处理 | ||
*/ | ||
responseInterceptorsCatch?: (axiosInstance: AxiosInstance, error: Error) => void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/** | ||
* @description: http常量 | ||
* @author: gbeata | ||
*/ | ||
export enum ResultEnum { | ||
SUCCESS = 0, | ||
ERROR = -1, | ||
TIMEOUT = 401, | ||
TYPE = 'success', | ||
} | ||
/** | ||
* @description: 请求方式 | ||
* @author: gbeata | ||
*/ | ||
export enum RequestEnum { | ||
GET = 'GET', | ||
POST = 'POST', | ||
PUT = 'PUT', | ||
DELETE = 'DELETE', | ||
} | ||
|
||
/** | ||
* @description: 常用Content Type | ||
* @author: gbeata | ||
*/ | ||
export enum ContentTypeEnum { | ||
// json | ||
JSON = 'application/json;charset=UTF-8', | ||
// form-data qs | ||
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8', | ||
// form-data upload | ||
FORM_DATA = 'multipart/form-data;charset=UTF-8', | ||
} |
Oops, something went wrong.