vue拦截器实现http+router双拦截
vue拦截器,主要是针对数据请求进行统一的调度,避免不同请求多个响应方式,以达到在交互上的统一,如统一的错误处理。在vue框架里实现http数据请求主要是通过
axios
,请求拦截使用interceptors
方法。
在实际项目开发过程中,经常有拦截请求、拦截响应,下面就先从这两个方面来说一说。
拦截请求
实用的场景是需要在http请求中增加自定义的header
信息,常见的就是在header
中增加通讯签名和凭证来防止攻击。下面看看代码片段:
const apiClient = axios.create({
baseURL: "/api",
});
// 拦截请求
apiClient.interceptors.request.use(request => { // 请求头添加access_token
const token = localStorage.getItem('TOKEN') ? JSON.parse(localStorage.getItem('TOKEN')) : ''
if (token && token.access_token) {
request.headers['Access-Token'] = token.access_token.value
}
/*
* 处理post、put、delete请求
* 1、data为空时,默认传一个随机参数
* 2、根据data生成签名
* 3、转化data为查询参数格式
*/
if (request.method === 'post' || request.method === 'put' || request.method === 'delete') {
// 默认传一个数据
if (!request.data) {
request.data = {
t: new Date().getTime()
}
}
// 请求头添加签名
request.headers.Sign = util.createSign(request.data)
// 转化data数据格式
request.data = qs.stringify(request.data)
}
return request
}, error => {
console.error(error.message)
})
拦截响应
这里主要是对请求的响应进行统一的拦截处理,常见的有统一的错误响应、判断登录的凭证是否过期等等。如下面代码片段:
// 拦截响应
apiClient.interceptors.response.use(res => {
// 响应失败
if (!res.data.success) {
// 请求失败响应处理
}
/**
* refresh_token过期
* 1、清空本地token
* 2、刷新页面
*/
if (res.data.code === 401) {
localStorage.setItem('token', '')
window.location.reload()
}
return res.data;
}, error => {
console.error(error.message);
})
下面来看看统一的错误处理,主要是http
响应的错误处理。
apiClient.interceptors.response.use(undefined, (error) => {
// Errors handling
const { response } = error;
const { data } = response;
if (data) {
// 此处为错误处理
notification.warning({
message: data,
});
}
});
请求Loading及登录状态处理
直接上代码,这里只是基本的实现逻辑,代码本身涉及其他依赖,并不能直接使用。
下面的片段实现对http请求的拦截处理。
// vue axios配置 发起请求加载loading请求结束关闭loading
// http request 请求拦截器,有token值则配置上token值
import axios from "axios";
import router from "../router";
import { Loading } from "element-ui";
import Promise from "promise";
let loadinginstace;
// http请求拦截器
axios.interceptors.request.use(
(request) => {
// element ui Loading方法
loadinginstace = Loading.service({
lock: true,
text: "Loading",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.3)",
customClass: "osloading",
fullscreen: true,
});
return request;
},
(error) => {
loadinginstace.close();
return Promise.reject(error);
}
);
// http response 服务器响应拦截器,
// 拦截401,并重新跳入登页重新获取token
axios.interceptors.response.use(
(response) => {
// 后端响应的数据结构为:{code:401,data:{}}
if (response.data.code === 401) {
loadinginstace.close();
router.replace({
path: "/login",
});
} else {
loadinginstace.close();
return response.data;
}
},
(error) => {
loadinginstace.close();
if (error.response) {
let routerPath = "/login";
switch (error.response.status) {
case 401:
routerPath = "/login"
break;
case 404:
routerPath = "/404"
break;
}
router.replace({
path: routerPath,
});
}
return Promise.reject(error.response.data);
}
);
export default axios;
路由登录验证处理
路由的拦截,主要的实现逻辑是在路由跳转之前进行验证,主要的登录状态的验证,复杂的应用还会涉及权限的验证。
import auth from "@/api/auth";
auth.refreshAuth();
router.beforeEach((to, from, next) => {
if (to.matched.some((record) => record.meta.requireAuth)) {
// 判断该路由是否需要登录权限
const isLogin = auth.checkAuth();
if (isLogin) {
// 判断当前的token是否存在
next();
} else {
next({
path: "/login",
});
}
} else {
next();
}
});