axios完整二次封装及使用
在前端项目中网络请求的封装必不可少,最近重构了下项目axios的封装故进行记录
axios二次封装
import axios from "axios";
import router from "../router"; //看具体项目封装的路由文件修改
//跳转登陆页面
const toLogin = () => {
router.replace({
path: "/login"
});
};
//封装状态码错误处理函数
const errorHandle = status => {
switch (status) {
//登录不成功时跳转到登录页面
case 401:
console.log("认证失败,未登录或无权限");
toLogin();
break;
case 403:
//token过期了,清除token存储
localStorage.removeItem("token");
console.log("token校验失败");
toLogin();
break;
case 404:
console.log("请求的资源不存在");
break;
default:
console.log("请求出错,状态码为:" + status);
break;
}
};
// axios二次封装
const devBaseURL = "在开发环境下接口的baseURL";
const proBaseURL = "在生产环境下接口的baseURL";
//在vue的config文件夹下可以看开发环境和生产环境的名称,通常为development和production
const baseURL = process.env.NODE_ENV === 'development' ? devBaseURL: proBaseURL;
//创建axios实例
const service = axios.create({
baseURL: baseUrl,
// 配置超时时间
timeout: 2000
});
//设置post请求的 Content-Type,需不需要写看后台规范
service.defaults.headers.post["Content-Type"] ="application/x-www-form-urlencoded";
//允许跨域传递cookie带上凭证,看具体项目,通常要设为true
service.defaults.withCredentials = true;
//ES6解构赋值,引入cancelToken和isCancel
const { CancelToken, isCancel } = axios;
//定义一个全局的变量存储不同的url,避免同一页面有多个请求时拦截了正常的请求
let pending = {};
// 设置axios的请求拦截器
service.interceptors.request.use(config => {
//获取本地存储中的token,若有token则加到请求中去,token一般存储到本地或者vuex
let token = localStorage.getItem("token");
token && (config.headers.Authorization = token);
//取消重复请求
//用每个请求的url当作唯一标识的key值取消重复请求
let key = config.url + "&" + config.method;
//若上一个请求已存在则调用函数取消上一次的重复请求
if (pending[key]) pending[key]("取消了重复请求");
config.cancelToken = new CancelToken((c) => {
// 将取消请求的函数c赋值给pending[key]保存取消函数
pending[key] = c;
});
//记得要返回config才可进行接下来的请求
return config;
});
//设置axios的响应拦截器
service.interceptors.response.use(
response => {
//成功则返回response里有用的data
return response.data
},
//失败则进行统一的错误处理
error => {
let { response } = error;
//判断是否为重复请求而出错
if (isCancel(error)) console.log("请求失败,原因是" + error.message);
else if (response) {
errorHandle(response.status);
}
//判断客户端有无联网
if (!window.navigator.onLine) {
//断网处理:跳转断网页面/提示网络错误等等
alert("请检查网络是否连接");
}
//出错中断promise链
return new Promise(() => {});
}
);
//导出封装的aixos
export default service;
使用
在接口管理文件中引入封装的service,在这里我仍起名为axios:
import axios from '封装的service所在路径';
在接口管理文件中进行api请求,接口数多时注意写好每个接口的功能方便后续调用:
//1.登录
export const login = data => axios.post("/user/login", data)//路径根据后台给的接口文档填写
// 2. 修改密码
export const updatePwd = data => axios.put("/user/password", data)
在页面中使用:
用import导入要用的接口,
import {login, updatePwd } from "@/api/index";
login().then(res=>console.log(res))
axios拦截器原理
当我们使用 Axios实例发送请求时get、post等方法实际都是调用的Axios.prototype.request
方法,最终返回的是promise链式调用,实际请求是在dispatchRequest
中发生的。
使用拦截器时axios调用request会创建一个chain数组(chain=[dispatchReauest,undefined],undefined只起占位作用,因为后续chain执行每次会取两个数)把请求拦截器放在dispatchReauest前面,响应拦截器放在undifined后面,然后按顺序遍历执行chain,每次取出两个数,一个是拦截器成功的函数一个是失败的函数对应传入promise成功的回调和失败的回调中,保证了请求拦截器——api请求——响应拦截器的执行顺序
注意:请求拦截器后设置的先执行,响应拦截器先设置的先执行