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();
    }
});
httpaxios