为了简化数据交互的代码以及后续代码的修改更新维护,在 Vue
项目中我们会需要对 axios 库进行进一步的封装并集中管理 api 数据请求;
axios
本质还是 ajax,不过是为了解决 ajax 繁琐的请求方式以及更好的处理回调;axios
是由 ajax 和 promise 封装的 HTTP 库; 主要这几个部分说明项目中前后端数据交互的请求管理
- 配置和创建
axios
实例 - 请求及响应的处理 (transformRequest 可以修改传输的数据,validateStatus 用于决定那些状态会被 catch 捕获以便于处理)
- api 接口的管理
首先考虑在 src
文件目录下建立文件夹及文件夹 api/http.js
我们代码的封装就在 http.js 内完成,为了防止 axios 被全局'污染',我们通过创建 axios 实例和配置项开始;
Axios 封装
区分环境 baseURL/超时/请求头格式修改
import axios from 'axios'
import qs from 'qs'
const service = axios.create{
// 区分状态,更换不同的URL
baseURL: process.env.NODE_ENV === 'production' ? 'productionUrl' : 'devUrl',
// 设置超时时间
timeOut: 10000,
}
// 设置post的请求头格式
service.defaults.headers.post['Content-Type'] =
'application/x-www-form-urlencoded;charset=UTF-8';
请求、响应处理 (拦截器)
transformRequest
允许在向服务器发送请求前,修改请求数据;transformResponse
在传递给 then/catch 前,允许修改响应数据- axios 提供了
validateStatus
属性,用于定义对于给定的HTTP
响应状态码是resolve
或reject
promise。 这里提及但是可以不作修改,默认status >= 200 && status < 300
, 其他状态均在onReject
中进行处理;
import router from '../router'
// 序列化数据请求
service.defaults.transformRequest = data => qs.stringify(data)
const backToLogin = () => {
router.replace({ path: '/login' })
}
// 根据 status 生成 msg 及操作
const handleErrStatus = status => {
switch (status) {
case 401:
backToLogin()
return '未授权,请重新登录'
case 403:
localStorage.removeItem('token')
store.commit('clearToken')
backToLogin()
return '登录过期,请重新登录'
case 404:
return '请求的资源不存在',
}
String(status).match(/^(5)/) && return '服务端出错,请联系管理员'
}
// 提示
import { Toast } from 'vant'
const showMsg = msg =>
Toast({ message: msg, duration: 1000, forbidClick: true })
// 处理请求部分的拦截
service.interceptor.request.use(
config => {
// 获取并设置 token
const token = store.state.token || localStorage.getItem('token')
token && (config.header.Authorization = token)
return config
},
err => {
Promise.error(err)
}
)
// 处理数据的响应
service.interceptor.response.use(
res => res,
error => {
const { response } = error
// 如果有response,则说明该请求已发起,但是错误
if (response) {
// 全局提示
showMsg(handleErrStatus(response.status))
return Promise.resolve(response)
}
return Promise.reject(error)
}
)
Api 的管理
为了避免重复的编写请求体以及集中管理,我们会对 get
及 post
请求做一次封装; 我们在 http.js
的同级下建立 api.js
;
先反过来,先确定我们想要怎样的调用形式,之后确定封装方式
//api
export const getDeviceList = data => get('api/Device/getDeviceList', data)
export const updateDevice = data => post('api/Device/updateDevice', data)
注: 当数据接口多的时候,使用模块化管理接口,api.js 为 api 集合的导出口, 而对应的模块内容参照如上所述的编写
// api.js
import funcModule1 from './funcModule1'
import funcModule2 from './funcModule2'
export default {
funcModule1,
funcModule2
}
如此,我们构建出返回值 Promise 对象的函数作为公用的函数
// http.js
export const get = (url, params, config = {}) => {
return new Promise((resolve, reject) => {
service({
methods: 'get',
url,
params
})
.then(res => resolve(res))
.catch(err => reject(err))
})
}
export const post = (url, data, config = {}) => {
return new Promise((resolve, reject) => {
service({
methods: 'post',
url,
data
...config
})
.then(res => resolve(res))
.catch(err => reject(err))
})
}