一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情。
前情提要
其实针对项目大小的程度不同,对axios封装的需求也全然不同。axios本身就是封装很不错的了,所以对于一般小项目而言完全没有二次封装的意义。而二次封装往往也会配合api的统一管理来进行使用。
而对于大项目而言,需求点主要在于针对接口返回错误信息的统一处理、后端接口域名在不同环境下的切换、对接口数据的二次清洗、有主动取消请求中的接口等私人订制化需求。
而对于项目接口规范不同二次封装的方式也不同。有的项目采用的resultfull风格的接口,有的项目可能永远就固定使用一种post请求等。
所以主要分两种:
根据具体请求进行封装:封装程度有限,可拓展性有限。
利用axios的拦截器进行封装:封装程度高,可拓展性高。属于目前最常见的一种封装方式
根据具体请求封装(基本上不是很推荐这种写法)
- 以post请求为例
- /utils/axios.js
import axios from 'axios';
// 环境的切换
if (process.env.NODE_ENV == 'development') {
axios.defaults.baseURL = 'http://aaaaaaaaaa.com';
}
else if (process.env.NODE_ENV == 'debug') {
axios.defaults.baseURL = 'https://yyyyyyyy.com';
}
else if (process.env.NODE_ENV == 'production') {
axios.defaults.baseURL = 'http://xxxxxxx.com';
}
axios.defaults.withCredentials = true;
axios.defaults.timeout = 30000;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
/**
* post方法,对应post请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function post(url, data) {
return new Promise((resolve, reject) => {
axios.post(url, data)
.then(res => {
console.log(res)
resolve(res.data);
})
.catch(err => {
reject(err.data)
})
});
}
- 如果项目使用了api统一管理:/api/index.js
import { axios } from '@/utils/axios'
export default {
getInfo(params) {
return axios('/xxx/xxx/xxx', params)
}
}
- 如果项目没有使用api统一管理:main.js
import Vue from 'vue'
import App from './App.vue'
import { post } from '@/utils/axios'
Vue.config.productionTip = false
Vue.prototype.$post = post
new Vue({
render: h => h(App),
}).$mount('#app')
利用axios拦截器进行封装
- 主要利用
请求拦截器
和响应拦截器
- 拦截器主要接受两个回调函数,一个是正常的回调函数,一个是错误回调函数。
- .env.development
BASE_URL = ‘xxxx’;
- /utils/axios.js
import axios from 'axios';
const service = axios.create({
// 如果不存在跨域问题并且在.env.xxx文件中有配置的话baseURL的值可以直接使用:process.env.BASE_URL;
//如果使用proxy做了代理配置,那么baseURL的值直接填写'/'就可以了。
baseURL: '',
timeout: 60000,
headers: { // 主要进行相关请求头信息配置
'Content-Type': ‘application/json;charset=UTF-8’,
'token': 'xxxxxxxxx'
}
})
// 请求拦截器:所有的请求在发起请求之初都会走这个
service.interceptors.request.use(
async (config) => {
```
上面的头部信息配置有些固定,毕竟有些接口的相关配置就那么标新立异,鹤立鸡群,那么就可以在这里
进行动态配置.比如:config.headers.token = 'xxxxxxxx'
```
// 如果需要对数据进行二次处理,同样可以在这里深度定制化处理
// 最后将动态处理好的config返回就行了。
return config;
},
(error) => {
return Promise.reject(error);
}
)
// 响应拦截器:所有的请求在响应之后都会走这个
service.interceptors.response.use(
(response) => {
// 此时接口已经请求成功,response里面便是请求成功后返回的响应体
// 一般情况下会在这里进行一次数据的剥离。这样真正发起请求的地方就可以少写一层
```
response里存在data对象,status,statusText,headers对象,config对象,request对象。
此时我们只需要data和config: const { data, config } = response;
```
```
项目里一般会存在文件请求,此时返回的response是二进制文件流,要做个判断:
const { responseType } = config; if(responseType == 'blob') return response; return data;
```
```
有时虽然请求是200,但是实际接口返回的可能不是正常数据,而是自定义的错误code,这时可以在这里进行相关
前后端协商后的相关配置。比如:code是404,则跳转到404页面。code是502,则跳转到502页面。code
是401,则跳转到401当然也不一定非要跳转页面,也可以引入Element实例然后弹出错误或者警告信息框。
```
return response;
},
(error) => {
return Promise.reject(error);
}
)
// 最后将service对象抛出去就行
export default service;