关于Axios二次封装
初识Axios二次封装
首先,我们需要明白为什么需要二次封装axios,在我们项目的实际开发过程中需要token,我们对于每个请求都需要附带一个请求字段 Authorization,但是我们不可能在每个请求的时候都写一遍,所以我们就需要利用axios的请求拦截,为我们的请求附带上Authorization字段。
其次,在后端服务为我们返回的响应中,我们会接收到对应的返回状态码,我们需要对这些状态码进行判断,并且需要展示给用户,例如状态码401,代表token过期。我们可以利用axios的响应拦截自动识别状态码,并且将对应的信息展示给用户,提高我们的开发效率。
最后,axios二次封装可以规范我们的请求风格,我们只需要传递一个options对象,对象包含请求方法method,请求参数data,请求路径url…。我们只需要传递这样一个对象,即可快速完成一个请求。
以上只是简单介绍axios二次封装的好处,总体来说,二次封装axios能帮助我们规范化、快速化地完成一个服务请求。
下面就让我们了解如何进行二次封装axios。
Axios二次封装的整体思路
1.创建一个axios实例对象。
2.对axios请求进行请求拦截。
3.进行响应拦截。
4.封装请求方法。
5.导出axios实例对象。
6.将axios实例对象挂载到vue原型上,方便使用。
Axios二次封装的完整实例
/**
* 封装axios请求
*/
import axios from 'axios';
import config from './../config'//环境配置封装文件
import {ElMessage} from 'element-plus'
import router from './../router'
import storage from './storage' //localStorage的二次封装
const TOKEN_INVALID = 'Token验证失败,请重新登录';
const NETWORK_ERROR = '网络请求异常,请稍后再试'
//创建axios实例对象,添加全局配置
const service = axios.create({
baseURL:config.baseApi,
timeout:8000,
})
//请求拦截
service.interceptors.request.use((req)=>{
//TODO:这里做一些请求拦截的处理
const headers = req.headers;//获取请求头
const {token} = storage.getItem('userInfo');//获取本地存储中的userInfo,解构出token
if(!headers.Authorization) headers.Authorization = `Bearer ${token}`;//附带上auth请求字段
return req;//返回请求对象
})
//响应拦截
service.interceptors.response.use((res)=>{
//TODO:这里做一些响应拦截
const {code ,data ,msg} = res.data;
if(code === 200){
return data;//若请求返回状态码为200,直接返回data数据,不用再返回响应对象res
}else if(code === 50001){
//token过期
ElMessage.error(TOKEN_INVALID);
setTimeout(()=>{
router.push('/login');
},1500)
return Promise.reject(TOKEN_INVALID);//重点!需要返回一个Promise的reject对象。
}else{
ElMessage.error(msg || NETWORK_ERROR);
return Promise.reject(msg || NETWORK_ERROR);
}
})
/**
* 请求核心函数
* @param {*} options 请求配置
* @returns axios实例对象
*/
function request(options){
options.method = options.method || 'get';//默认为get请求方法
if(options.method.toLowerCase() === 'get'){//如果为get请求方法,需要将data转化为params
options.params = options.data;
}
let isMock = config.mock;//查看是否使用mock接口
if(typeof options.mock != 'undefined'){
isMock = options.mock;
}
if(config.env === 'prod'){
service.defaults.baseURL = config.baseApi
}else{
service.defaults.baseURL = isMock? config.mockApi : config.baseApi
}
return service(options)//返回一个Promise对象
}
/**组件中调用request方法
this.$request({
url: "/users/login",
method: "post",
data: {},
mock:false,
}).then((res)=>{}).catch((err)=>{})
*/
//导出axios实例对象
export default request;
对于上述代码的mock接口,其实就是当我们后端服务接口还没完成时,我们前端开发人员可以使用mock接口快速模拟生成假数据,测试我们的请求是否有问题。这样就不必等后端服务接口开发完,我们才进行测试我们的请求书否正确。
个人推荐使用fastmock,apipost进行模拟mock接口。
mock使用了解
如何使用Axios二次封装请求
对于使用我们封装完的axios,只需要在项目根目录下的main.js中进行挂载即可。
import request from "./utils/request.js";
import storage from "./utils/storage.js";
Vue3项目使用:
app.config.globalProperties.$request = request;//axios二次封装
app.config.globalProperties.$storage = storage;//localstorage二次封装
vue2项目使用:
Vue.prototype.$request = request;
Vue.prototype.$storage = storage;
附录:如何在vue中获取环境变量(了解)
在我们项目实际开发过程中,有分开发环境dev、测试环境test、生产环境prod。在每个环境中,对应的baseUrl都是不一样的,但是我们不可能手动去修改baseUrl,这样不仅麻烦,且容易出错。因此,我们需要在项目运行时自动获取当前对应的环境,然后获取该环境所对应的baseUrl。
首先,我们需要在项目根目录下创建对应的env环境文件,例如
.env.dev、.env.test、.env.prod
.env.dev文件
NODE_ENV=dev
.env.test文件
NODE_ENV=test
.env.prod文件
NODE_ENV=prod
接着,我们需要在package.json文件中,对启动命令添加环境。
"scripts": {
"dev": "vue-cli-service serve --mode dev",
"build": "vue-cli-service build"
},
最后,创建一个环境配置封装文件
/**
* 环境配置封装
*
*/
//默认生产环境
const env = import.meta.env.MODE || 'prod';
//vue2通过process.env.NODE_ENV获取环境变量
const EnvConfig = {
dev:{
baseApi:'xxx',
mockApi:'xxx'
},
test:{
baseApi:'xxx',
mockApi:'xxx'
},
prod:{
baseApi:'xxx',
mockApi:'xxx'
}
}
export default{
env,
mock:false,
namespace:'manager',
...EnvConfig[env]
}
附录:如何封装LocalStorage(了解)
对于封装localstorage作者就不再做过多叙述,下面直接展示封装案例。
/**
* storage二次封装
*/
import config from './../config' //环境配置文件
export default{
setItem(key,val){
let storage = this.getStorage();
storage[key] = val;
window.localStorage.setItem(config.namespace,JSON.stringify(storage));
},
getItem(key){
return this.getStorage()[key];
},
getStorage(){
return JSON.parse(window.localStorage.getItem(config.namespace) || "{}");
},
clearItem(key){
let storage = this.getStorage();
delete storage[key];//关键!
window.localStorage.setItem(config.namespace,JSON.stringify(storage));
},
clearAll(){
window.localStorage.clear();
}
}