注意:本文实例化为TS版
1、axios概念
axios 是一个基于 promise 封装的网络请求库,它是基于 原生XHR 进行二次封装,可以说是 XHR 的一个子集,而 XHR 又是 Ajax 的一个子集
特点
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
2、axios封装源码
核心文件展示
2.1、index.ts
import axios from 'axios'
import NProgress from 'nprogress'
import { requestInterceptors, requestInterceptorsCatch, responseInterceptors, responseInterceptorsCatch } from './interceptors'
import { getPromise, formPostPromise, postPromise, exportPromise, uploadPromise, postExportPromise } from './requestPromise'
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
import { getSession } from '@/utils/storage'
const baseUrl = '' // 你的接口请求地址
const service: AxiosInstance = axios.create({
baseURL: baseUrl,
timeout: 10 * 1000, // 请求超时时间
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
// 请求前的处理
const requestHook = function (config: AxiosRequestConfig) {
NProgress.start()
const token = getSession('token')
if (token) {
config.headers.Authorization = token
}
}
// 请求前的错误处理
const requestCatchHook = function (error: AxiosError) {
console.log(error, 'requestCatchHook') // for debug
}
// 过期回调
const responseExpireHook = function (response: AxiosResponse) {
// 过期回调处理 此处写你自己的逻辑
return response
}
// 响应完成回调
const responseFinishCallback = function (e: any) {
NProgress.done()
}
// request interceptor
service.interceptors.request.use(requestInterceptors(requestHook), requestInterceptorsCatch(requestCatchHook))
// response interceptor
service.interceptors.response.use(
responseInterceptors(responseExpireHook, responseFinishCallback),
responseInterceptorsCatch(responseExpireHook, responseFinishCallback)
)
export const get = (url: string, params?: any) => getPromise(service, url, params) // get 请求
export const post = (url: string, params?: any) => postPromise(service, url, params) // post 请求
export const formPost = (url: string, params?: any) => formPostPromise(service, url, params) // form post
export const exportExcel = (url: string, params: any) => exportPromise(service, url, params) // 导出
export const upload = (url: string, files: Blob, config?: AxiosRequestConfig) => uploadPromise(service, url, files, config) // 上传
export const postExcel = (url: string, paramss: any) => postExportPromise(service, url, paramss)
export default service
2.2、interceptors.ts
import type { AxiosRequestConfig, AxiosResponse, AxiosError, AxiosPromise } from 'axios'
import { ElMessage } from 'element-plus'
// 下面响应结果的结构为普遍使用,但可根据你们公司自己规则来定
interface Result<T = any> {
code: number | string
msg?: string
message?: string
data: T
}
export const requestInterceptors =
(requestHook: Function) =>
(config: AxiosRequestConfig): AxiosRequestConfig => {
requestHook && requestHook(config)
return config
}
export const requestInterceptorsCatch =
(requestCatchHook: Function) =>
(error: AxiosError): AxiosPromise => {
requestCatchHook && requestCatchHook(error)
return Promise.reject(error)
}
export const responseInterceptors =
(responseHook: Function, responseCallback: Function) =>
(response: AxiosResponse): any => {
responseCallback && responseCallback(response)
const res: Result = response.data
if (response.config.responseType == 'blob') {
return Promise.resolve(response)
} else {
if (res === void 0 || res === null || !res) {
const message: string = `Error:${response.config.url} response.data is null or does not exist !`
ElMessage.error(message)
return Promise.reject(message)
// 接口响应code码我默认1或者200是正常响应,这个值根据你们后端的逻辑来定噢
} else if (res.code == 1 || res.code === 200) {
// 正确响应
res.data === null && console.log(response)
return Promise.resolve(response)
} else {
return Promise.resolve(response)
}
}
}
export const responseInterceptorsCatch =
(responseCatchHook: Function, responseCallback: Function) =>
(error: AxiosError): AxiosPromise => {
responseCallback && responseCallback(error)
if (error && error.response) {
// 以下外部状态码是常规普遍使用的噢~你也可以根据你们公司自己逻辑来定
switch (error.response.status) {
case 400:
error.message = '请求错误(400)'
break
case 401:
error.message = '未授权,请重新登录(401)'
break
case 403:
if (error.response.data && error.response.data.code === 5001) {
error.message = error.response.data.msg
} else {
error.message = '拒绝访问(403)'
}
break
case 404:
error.message = '请求出错(404)'
break
case 408:
error.message = '请求超时(408)'
break
case 500:
error.message = '服务器错误(500)'
break
case 501:
error.message = '服务未实现(501)'
break
case 502:
error.message = '网络错误(502)'
break
case 503:
error.message = '服务不可用(503)'
break
case 504:
error.message = '网络超时(504)'
break
case 505:
error.message = 'HTTP版本不受支持(505)'
break
default:
error.message = `连接出错(${error.response.status})!`
}
}
if (error.message && error.message.indexOf('timeout') !== -1) {
error.message = '请求超时'
}
if (error.response?.data && error.response.data.code === 5001) {
// 过期
return responseCatchHook && responseCatchHook(error)
}
error.message && ElMessage.error(error.message)
return Promise.reject({ ...error.response })
}
2.3、requestPromise.ts
import type {
AxiosInstance,
AxiosRequestConfig
} from 'axios'
// 下面响应结果的结构为普遍使用,但可根据你们公司自己规则来定
interface Result<T = any> {
code: number | string
msg?: string
message?: string
data: T
}
// 默认格式下的post
export const postPromise = (service: AxiosInstance, url: string, params: any): Promise < Result > =>
new Promise((resolve, reject) => {
service
.post(url, params)
.then((response) => resolve(response.data))
.catch((err) => {
reject(err)
})
})
// 表单格式下的post
export const formPostPromise = (service: AxiosInstance, url: string, params: any): Promise < any > =>
new Promise((resolve, reject) => {
const formdata = new FormData()
for (const [k, v] of Object.entries(params)) {
formdata.append(k, v as string)
}
service
.post(url, formdata)
.then((response) => {
resolve(response.data)
})
.catch((err) => {
reject(err)
})
})
// 默认格式下的get
export const getPromise = (service: AxiosInstance, url: string, params: any): Promise < Result > =>
new Promise((resolve, reject) => {
service
.get(url, {
params
})
.then((response) => resolve(response.data))
.catch((err) => {
reject(err)
})
})
// 默认格式下的导出文件 post类型
export const postExportPromise = (service: AxiosInstance, url: string, params: any): Promise < any > =>
new Promise((resolve, reject) => {
service({
method: 'post',
url: url,
data: {
...params
},
responseType: 'blob'
})
.then((response) => {
const res = response.data
const filename = decodeURI(response.headers['content-disposition'].split(';')[1].split('filename=')[1])
resolve({
res,
filename
})
})
.catch((err) => {
reject(err)
})
})
// 默认格式下的导出文件 get类型
export const exportPromise = (service: AxiosInstance, url: string, params: any): Promise < any > =>
new Promise((resolve, reject) => {
service({
method: 'get',
url: url,
params,
responseType: 'blob'
})
.then((response) => {
const res = response.data
try {
const filename = decodeURI(response.headers['content-disposition'] ?.split(';')[1].split('filename=')[1])
let blob = new Blob([res])
let downloadElement = document.createElement('a')
let href = window.URL.createObjectURL(blob) //创建下载的链接
downloadElement.href = href
downloadElement.download = filename //下载后文件名
document.body.appendChild(downloadElement)
downloadElement.click() //点击下载
document.body.removeChild(downloadElement) //下载完成移除元素
window.URL.revokeObjectURL(href) //释放掉blob对象
resolve({
res,
filename
})
} catch (error) {
console.log(error)
reject({
res,
filename: ''
})
}
})
.catch((err) => {
reject(err)
})
})
// 表单格式下的上传文件
export const uploadPromise = (service: AxiosInstance, url: string, files: Blob, config?: AxiosRequestConfig): Promise < any > =>
new Promise((resolve, reject) => {
config && (config.headers['Content-Type'] = 'multipart/form-data')
service
.post(url, files, config)
.then((res) => {
resolve(res.data)
})
.catch((err) => {
console.log(err, 'err')
reject(err)
})
})
3、接口实例配置文件
举例api文件夹在有个qrCode模块
实例源码
import { get, post, formPost, exportExcel } from '@/request/index'
export function checkPdfRecord(params: object) {
return get('/api/xxx', params)
}
export function updatePdf(params: object) {
return post('/api/xxx', params)
}
4、接口调用实例
import {
checkPdfRecord
} from '@/api/qrCode';
checkPdfRecord(params).then(res => {
}).finally(() => {
})
5、拓展知识
5.1、Fetch
Fetch是在 ES6 出现的,它使用了 ES6 提出的 promise 对象。它是 XMLHttpRequest 的替代品。
- 使用 promise,不使用回调函数。
- 采用模块化设计,比如 rep、res 等对象分散开来,比较友好。
- 通过数据流对象处理数据,可以提高网站性能。
5.2、Ajax
Ajax 是一个技术统称,是一个概念模型,它囊括了很多技术,并不特指某一技术,它很重要的特性之一就是让页面实现局部刷新,是fetch和XMLHttpRequest的父级
5.3、多环境如何配置
根据环境变量文件来噢(开发模式或生产模式根据package.json)
package.json文件
"scripts": {
"dev": "vite --mode development",
"test": "vite --mode release",
"buildTest": "vite build --mode release",
"buildProduct": "vite build --mode production"
}
有不懂的可以直接评论噢~欢迎点赞收藏~