Partition code file structure
config
: Exports some global variablestype
: Defines a type interfaceindex
: the wrapper file of Axios
The config file
// Set the request timeout.
// Change the baseUrl according to the environment
let BASE_URL = ' '
const TIME_OUT = 5000
if (process.env.NODE_ENV === 'development') {
BASE_URL = 'development'
} else if (process.env.NODE_ENV === 'production') {
BASE_URL = 'production'
} else {
BASE_URL = 'test'
}
export { BASE_URL, TIME_OUT }
Copy the code
Type the file
If we don’t wrap Axios, we can just use the types provided by Axios. But we need to provide an interceptor function and also show loading, so we need to extend some built-in interfaces.
import type { AxiosRequestConfig, AxiosResponse } from 'axios'
// Define the incoming interceptor interface, and both are optional.
interface IRequestInterceptors<T = AxiosResponse> {
// Interceptor when the request succeedsrequestSuccessInterceptor? :(config: AxiosRequestConfig) = > AxiosRequestConfig
// Interceptor when the request failsrequestErrorInterceptor? :(err: any) = > any
// Interceptor for successful responseresponseSuccessInterceptor? :(res: T) = > T
// Interceptor when the response failsresponseErrorInterceptor? :(err: any) = > any
}
// This interface will replace AxiosRequestConfig
export interface IRequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
// Each request instance can pass without interceptorsinterceptors? : IRequestInterceptors<T>// Whether to display loadingshowLoading? :boolean
}
Copy the code
The index file
We wrap AXIOS with classes that allow it to create multiple INSTANCES of AXIOS. It has its own unique state.
Defines the global interceptor for AXIos
His goal is that each AXIos instance and request needs to do something that we can put in the global interceptor. We define the logic of the interceptor in the constructor.
import axios, { AxiosInstance } from 'axios'
import { IRequestConfig } from './type'
class Request {
public instance: AxiosInstance
constructor(config: IRequestConfig) {
this.instance = axios.create(config)
// Create a global request interceptor
this.instance.interceptors.request.use(
(config) = > {
console.log('Global request successfully created interceptor')
return config
},
(err) = > {
console.log('Interceptor created by global request failure')
return err
}
)
// Create global response interceptor
this.instance.interceptors.response.use(
(config) = > {
console.log('Global response successfully created interceptor')
return config
},
(err) = > {
console.log('Interceptor created for global response failure')
return err
}
)
}
}
Copy the code
Define an instance interceptor for AXIos
These interceptors are just as global as if multiple AXIOS instances were not created. In most cases, we don’t need to create multiple instances of AXIos. This is where our extended AxiosRequestConfig interface comes in handy. These interceptors we need to pass in the corresponding logic when creating the instance. Then register in the constructor.
import axios, { AxiosInstance } from 'axios'
import { IRequestConfig } from './type'
class Request {
public instance: AxiosInstance
constructor(config: IRequestConfig) {
this.instance = axios.create(config)
// Create instance request interceptor
this.instance.interceptors.request.use(
config.interceptors?.requestSuccessInterceptor,
config.interceptors?.requestErrorInterceptor
)
// Create instance request interceptor
this.instance.interceptors.response.use(
config.interceptors?.responseSuccessInterceptor,
config.interceptors?.responseErrorInterceptor
)
}
}
Copy the code
encapsulationrequest
function
This is a call to the request function in AXIos.
We know the benefits of promises, so we return request as a Promise object. But the promise needs to pass in a generic type as the type of the return value. So we need to pass in a return value type when we call the request function. And we can create an interceptor unique to a single request here. These interceptors need to pass in the corresponding logic when calling the Request function. And calls the interceptor passed in and returns its value to the configuration object or return value.
// The generic passed in is the constraint return value
request<T>(config: IRequestConfig<T>): Promise<T> {
return new Promise((resolve, reject) = > {
// Create a request interceptor for a single request
if (config.interceptors?.requestSuccessInterceptor) {
// call directly, and then return the processed config
config = config.interceptors.requestSuccessInterceptor(config)
}
this.instance
.request<any, T>(config)
.then((res) = > {
// Invoke the incoming response interceptor
if (config.interceptors?.responseSuccessInterceptor) {
res = config.interceptors.responseSuccessInterceptor(res)
}
resolve(res)
})
.catch((err) = > {
reject(err)
})
})
}
Copy the code
Encapsulate other request methods.
These methods use the request method encapsulated above.
get<T>(config: IRequestConfig<T>): Promise<T> {
return this.request<T>({ ... config,method: 'GET' })
}
post<T>(config: IRequestConfig<T>): Promise<T> {
return this.request<T>({ ... config,method: 'POST'})}delete<T>(config: IRequestConfig<T>): Promise<T> {
return this.request<T>({ ... config,method: 'DELETE' })
}
patch<T>(config: IRequestConfig<T>): Promise<T> {
return this.request<T>({ ... config,method: 'PATCH'})}Copy the code
Loading is done via element-plus
Loading components can be loaded via Elder-plus. And call it as a service. Note the type import path for the new version.
import { ILoadingInstance } from 'element-plus/lib/components/loading'
import axios, { AxiosInstance } from 'axios'
import { IRequestConfig } from './type'
import { ElLoading } from 'element-plus/lib/components'
// Default loading loading
const DEFAULT_LOADING = true
// Define two attributes
public showLoading: boolean
publicloadingInstance? : ILoadingInstanceconstructor(config: IRequestConfig) {
// Loading is not loaded by default
this.showLoading = config.showLoading ?? DEFAULT_LOADING
this.instance = axios.create(config)
// Create a global request interceptor
this.instance.interceptors.request.use(
(config) = > {
console.log('Global request successfully created interceptor')
// Loading loading occurs when showLoading is true
if (this.showLoading) {
// Add loading loading
this.loadingInstance = ElLoading.service({
text: 'Loading, please wait... '.background: 'rgba(0, 0, 0, .1)'.lock: true})}return config
},
(err) = > {
console.log('Interceptor created by global request failure')
// An error is requested to disable loading
this.loadingInstance? .close()return err
}
)
// Create global response interceptor
this.instance.interceptors.response.use(
(config) = > {
console.log('Global response successfully created interceptor')
// Turn loading off in response
this.loadingInstance? .close()return config
},
(err) = > {
console.log('Interceptor created for global response failure')
// Turn loading off when the response fails
this.loadingInstance? .close()return err
}
)
}
// The generic passed in is the constraint return value
request<T>(config: IRequestConfig<T>): Promise<T> {
return new Promise((resolve, reject) = > {
// Specify whether to load the request. When this parameter is passed, the default is true
if (config.showLoading === false) {
this.showLoading = false
}
// Create a request interceptor for a single request
if (config.interceptors?.requestSuccessInterceptor) {
// call directly, and then return the processed config
config = config.interceptors.requestSuccessInterceptor(config)
}
this.instance
.request<any, T>(config)
.then((res) = > {
// After a single request ends, loading is set to the default value. Since we mounted showLoading to the Request instance, the state was constantly changed
this.showLoading = DEFAULT_LOADING
// Invoke the incoming response interceptor
if (config.interceptors?.responseSuccessInterceptor) {
res = config.interceptors.responseSuccessInterceptor(res)
}
resolve(res)
})
.catch((err) = > {
// After a single request ends, loading is set to the default value. Since we mounted showLoading to the Request instance, the state was constantly changed
this.showLoading = DEFAULT_LOADING
reject(err)
})
})
}
Copy the code
Complete index file code
import { ILoadingInstance } from 'element-plus/lib/components/loading'
import axios, { AxiosInstance } from 'axios'
import { IRequestConfig } from './type'
import { ElLoading } from 'element-plus/lib/components'
const DEFAULT_LOADING = true
class Request {
public instance: AxiosInstance
public showLoading: boolean
publicloadingInstance? : ILoadingInstanceconstructor(config: IRequestConfig) {
// Loading is not loaded by default
this.showLoading = config.showLoading ?? DEFAULT_LOADING
this.instance = axios.create(config)
// Create an instance request interceptor
this.instance.interceptors.request.use(
config.interceptors?.requestSuccessInterceptor,
config.interceptors?.requestErrorInterceptor
)
// Create an instance request interceptor
this.instance.interceptors.response.use(
config.interceptors?.responseSuccessInterceptor,
config.interceptors?.responseErrorInterceptor
)
// Create a global request interceptor
this.instance.interceptors.request.use(
(config) = > {
console.log('Global request successfully created interceptor')
if (this.showLoading) {
// Add loading loading
this.loadingInstance = ElLoading.service({
text: 'Loading, please wait... '.background: 'rgba(0, 0, 0, .1)'.lock: true})}return config
},
(err) = > {
console.log('Interceptor created by global request failure')
this.loadingInstance? .close()return err
}
)
// Create global response interceptor
this.instance.interceptors.response.use(
(config) = > {
console.log('Global response successfully created interceptor')
setTimeout(() = > {
this.loadingInstance? .close() },3000)
return config
},
(err) = > {
console.log('Interceptor created for global response failure')
this.loadingInstance? .close()return err
}
)
}
// The generic passed in is the constraint return value
request<T>(config: IRequestConfig<T>): Promise<T> {
return new Promise((resolve, reject) = > {
// Specify whether to load the request. When this parameter is passed, the default is true
if (config.showLoading === false) {
this.showLoading = false
}
// Create a request interceptor for a single request
if (config.interceptors?.requestSuccessInterceptor) {
// call directly, and then return the processed config
config = config.interceptors.requestSuccessInterceptor(config)
}
this.instance
.request<any, T>(config)
.then((res) = > {
this.showLoading = DEFAULT_LOADING
// Invoke the incoming response interceptor
if (config.interceptors?.responseSuccessInterceptor) {
res = config.interceptors.responseSuccessInterceptor(res)
}
resolve(res)
})
.catch((err) = > {
this.showLoading = DEFAULT_LOADING
reject(err)
})
})
}
get<T>(config: IRequestConfig<T>): Promise<T> {
return this.request<T>({ ... config,method: 'GET' })
}
post<T>(config: IRequestConfig<T>): Promise<T> {
return this.request<T>({ ... config,method: 'POST'})}delete<T>(config: IRequestConfig<T>): Promise<T> {
return this.request<T>({ ... config,method: 'DELETE' })
}
patch<T>(config: IRequestConfig<T>): Promise<T> {
return this.request<T>({ ... config,method: 'PATCH'}}})export default Request
Copy the code
test
import Request from './http/request'
import { BASE_URL, TIME_OUT } from './http/request/config'
const request = new Request({
baseURL: BASE_URL,
timeout: TIME_OUT,
showLoading: true.interceptors: {
requestSuccessInterceptor(config) {
console.log('Request instance requested interceptor successfully ')
return config
},
requestErrorInterceptor(err) {
console.log('Request instance Request failed interceptor ')
return err
},
responseSuccessInterceptor(res) {
console.log('Request instance responds successfully to interceptor ')
return res
},
responseErrorInterceptor(err) {
console.log('Interceptor failed to respond to Request instance')
return err
}
}
})
interface IRequestData {
data: any
}
request
.get<IRequestData>({
url: 'search? Keywords = Sea and sky '.showLoading: true.interceptors: {
requestSuccessInterceptor(config) {
console.log('Get request interceptor')
return config
}
}
})
.then((res) = > {
console.log('res ====', res)
})
Copy the code