axios二次封装
1、安装依赖
npm i -S axios qs
2、创建axios实例
const baseURL = 'http://127.0.0.1:8080/api'
const service = axios.create({
baseURL,
timeout: 30000,
withCredentials: false,
})
3、设置请求类型
service.defaults.headers.post['Content-Type'] = 'application/json;charset=utf-8'
service.defaults.headers.put['Content-Type'] = 'application/json;charset=utf-8'
4、配置多次请求取消方法
4.1、全局声明一个 Map 用于存储每个请求的标识 和 取消函数
const pending = new Map()
4.2、添加请求方法
const addPending = (config: AxiosRequestConfig): void => {
const url = [config.baseURL, config.method, config.url].join('')
config.cancelToken = new axios.CancelToken(cancel => {
if (!pending.has(url)) {
pending.set(url, cancel)
}
})
}
4.3、移除请求方法
const removePending = (config: AxiosRequestConfig): void => {
const url = [config.baseURL, config.method, config.url].join('')
if (pending.has(url)) {
const cancel = pending.get(url)
cancel(url)
pending.delete(url)
}
}
5、配置拦截器
5.1、请求拦截器
service.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
removePending(config)
addPending(config)
if (getToken()) {
config.headers.Authorization = getToken()
}
return config
},
error => {
console.log('请求异常', error)
error.data = {}
error.data.code = -1
error.data.message = '发送请求出现异常!'
return Promise.reject(error)
},
)
5.2、响应拦截器
service.interceptors.response.use(
(response: AxiosResponse) => {
removePending(response)
if (response.status === 200) {
const { code } = response.data
if (code === 200) {
return Promise.resolve(response.data)
} else {
return Promise.reject(response.data)
}
} else {
console.log('响应请求异常', response)
return Promise.reject(response)
}
},
error => {
if (axios.isCancel(error)) {
return new Promise(() => {})
}
console.log('响应请求出现异常!', error)
error.data = {}
error.data.code = -2
error.data.message = '响应请求出现异常!'
return Promise.reject(error.data)
},
)
6、封装返回数据接口
interface HttpResponse<T> {
code?: number
data: T
message?: string
}
7、完整代码
import { message } from 'antd'
import type { AxiosError, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
import axios from 'axios'
import Qs from 'qs'
import store from '@/store'
type Method = 'get' | 'post' | 'put' | 'delete'
type ResError = {
code: number
errMessage: string
}
interface IResult<T> {
code: number
data: T
message: string
}
const baseURL = 'http://127.0.0.1:8080'
const service = axios.create({
baseURL,
timeout: 30000,
withCredentials: true,
})
const ContentType = {
json: 'application/json;charset=utf-8',
form: 'application/x-www-form-urlencoded;charset=UTF-8',
multipart: 'multipart/form-data',
}
service.defaults.headers.post['Content-Type'] = ContentType.json
service.defaults.headers.put['Content-Type'] = ContentType.json
const pending = new Map()
const addPending = (config: AxiosRequestConfig) => {
const url = [config.baseURL, config.method, config.url].join('')
config.cancelToken = new axios.CancelToken(cancel => {
if (!pending.has(url)) {
pending.set(url, cancel)
}
})
}
const removePending = (config: AxiosRequestConfig) => {
const url = [config.baseURL, config.method, config.url].join('')
if (pending.has(url)) {
const cancel = pending.get(url)
cancel(url)
pending.delete(url)
}
}
const getToken = (): string | undefined => store.getState().loginUser.token
const showErrorMessage = (errorMessage: string) => message.error(errorMessage)
const handleResponseError = (error: AxiosError): ResError => {
let errMessage = '服务器未知错误!'
let code = -1
if (error.code === 'ERR_NETWORK') {
if (!window.navigator.onLine) {
errMessage = '请检查你的网络是否正常!'
} else {
errMessage = '服务器运行异常,请联系管理人员!'
}
} else if (error.response) {
code = error.response.status
switch (code) {
case 400:
errMessage = '错误的请求'
break
case 401:
errMessage = '未授权,请重新登录'
break
case 403:
errMessage = '拒绝访问'
break
case 404:
errMessage = '请求错误,未找到该资源'
break
case 405:
errMessage = '请求方法未允许'
break
case 408:
errMessage = '请求超时'
break
case 500:
errMessage = '服务器端出错'
break
case 501:
errMessage = '网络未实现'
break
case 502:
errMessage = '网络错误'
break
case 503:
errMessage = '服务不可用'
break
case 504:
errMessage = '网络超时'
break
case 505:
errMessage = 'http版本不支持该请求'
break
default:
errMessage = `其他连接错误 --${code}`
}
}
return { code, errMessage }
}
service.interceptors.request.use((config: InternalAxiosRequestConfig) => {
removePending(config)
addPending(config)
if (getToken()) {
config.headers.Authorization = getToken()
}
return config
})
service.interceptors.response.use(
(response: AxiosResponse) => {
removePending(response)
if (response.status === 200) {
const { code } = response.data
if (code === 200) {
return Promise.resolve(response.data)
} else {
const errMessage = response.data.message
console.log('这是系统自定义异常,异常信息为:' + errMessage)
showErrorMessage(errMessage)
const resError: ResError = { code, errMessage }
return Promise.reject(resError)
}
} else {
const errMessage = '服务器响应异常!'
console.log(errMessage, response)
showErrorMessage(errMessage)
const resError: ResError = { code: -2, errMessage }
return Promise.reject(resError)
}
},
error => {
if (axios.isCancel(error)) {
return new Promise(() => { })
}
const resError = handleResponseError(error)
console.log(resError, error)
showErrorMessage(resError.errMessage)
return Promise.reject(resError)
},
)
export const request = <T = any>(
url: string,
method: Method,
data?: unknown,
config?: AxiosRequestConfig,
): Promise<IResult<T>> => {
let newConfig = { ...config }
if (method === 'get' || method === 'delete') {
newConfig = { ...config, paramsSerializer: data => Qs.stringify(data, { indices: false }) }
}
return service<T, IResult<T>>({
url,
method,
[method.toLowerCase() === 'get' || method.toLowerCase() === 'delete' ? 'params' : 'data']: data,
...newConfig,
})
}
export const requestPro = <T = any, U = ResError>(
url: string,
method: Method,
data?: unknown,
config?: AxiosRequestConfig,
): Promise<[U, undefined] | [null, IResult<T>]> => {
let newConfig = { ...config }
if (method === 'get' || method === 'delete') {
newConfig = { ...config, paramsSerializer: data => Qs.stringify(data, { indices: false }) }
}
return service<T, IResult<T>>({
url,
method,
[method.toLowerCase() === 'get' || method.toLowerCase() === 'delete' ? 'params' : 'data']: data,
...newConfig,
})
.then<[null, IResult<T>]>(res => [null, res])
.catch<[U, undefined]>(err => [err, undefined])
}