likes
comments
collection
share

axios拦截器重发请求,更新token

作者站长头像
站长
· 阅读数 20

演示开发环境

编辑器:VsCode Vue:3.3.4 TypeScript:5.0.2 Element-Plus:2.3.7 Axios:1.4.0

依赖安装

Element-Plus:npm install element-plus --save

Axios:npm install axios --save

问题说明

ps:在我们开发的过程中,前端工程师 不可避免的一课就是处理 token(令牌),token有很多用途,常见的就是用于 用户认证鉴权接口鉴权 等等,本文就拿这两个来展开叙述

axios 配置文件

1、新建一个 axiosConfig.ts 文件

2、在文件中配置 请求路径请求超时时间 ...等等,这里我只讲以下配置

ps:变量名称、函数名称可 自定义,为方便演示函数内容比较简单,具体可根据 实际情况 调整

    // token本地存储关键词(相当于取本地token的钥匙)
    tokenLocalKey: 'xxxx',

    // token本地存储时间(单位:毫秒)
    // 具体时间根据实际情况而定,这里设置为120分钟,
    // 是因为我的后端接口返回的token有效期为120分钟
    tokenLocalSaveTime: 120 * 60 * 1000,

    // 保存token的函数
    // 参数:存储key、token信息、存储时间
    saveToken: (key: string, token: string, expire: number) => {
        // 声明存储内容对象
        const obj = {
            token: token, // token信息
            expire: Date.now() + expire // token有效时间
        };
        // 将内容存储到localStorage,内容格式为json字符串
        localStorage.setItem(key, JSON.stringify(obj));
    },

    // 加载token的函数
    // 参数:存储key
    loadToken: (key: string) => {
        // 获取本地存储的信息对象
        const localInfo = localStorage.getItem(key);
        if (localInfo) {
            // 获取token信息,并返回
            const { token } = JSON.parse(localInfo);
            return token;
        }
    },

    // 校验token是否过期
    // 参数:存储key
    checkToken: (key: string) => {
        // 获取本地存储的信息对象
        const localInfo = localStorage.getItem(key);
        if (localInfo) {
            // 获取token有效时间
            const { expire } = JSON.parse(localInfo);
            // 校验token是否过期,过期则移除token
            if (Date.now() > expire) {
                localStorage.removeItem(key);
            }
        }
    }

axios 拦截器配置

ps:拦截器具体内容根据 实际需求 而定,不一定要使用我的逻辑

在封装 axios 请求的文件中引入以下依赖

// 引入 axios 库
import axios from 'axios';
// 引入 axios 配置文件,路径以实际项目为准
import axiosConfig from 'xxxx/axiosConfig';
// 引入 element-plus 的 ElMessage 组件
import { ElMessage } from 'element-plus';
// 引入 element-plus 的样式文件
import 'element-plus/dist/index.css';

请求拦截器 - request interceptors

// axios 请求拦截器
axios.interceptors.request.use(
    (req) => {
        // 控制台打印请求内容
        console.log('请求拦截内容:{}', req);
        // 执行token过期校验
        axiosConfig.checkToken(axiosConfig.tokenLocalKey);
        // 继续请求
        return req;
    },
    (err) => {
        // 控制台打印错误
        console.log(err);
        // 使用组件提示错误内容
        ElMessage({
            message: `请求时出错: ${err} !`,
            type: 'error',
            showClose: true,
            center: true
        });
    }
);

响应拦截器 - response interceptors

// axios 响应拦截器
axios.interceptors.response.use(
    async (resp) => {
        // 控制台打印响应内容
        console.log('响应拦截内容:{}', resp);
        // 判断响应代码是否符合鉴权失败,这里的 1000 为后端接口返回鉴权失败的代码
        if (resp.data.code && resp.data.code === 1000) {
            // 获取请求的配置信息对象
            let config = resp.config;
            // 创建鉴权的 Promise 函数,这里因需求而异
            // 我这里的token需要调用接口获取,所以需要用到异步函数
            const authentication = new Promise((resolve) => {
                // 调用封装的 axios 请求函数
                ajax(
                    '/请求路径',
                    '请求参数',
                    (data: any) => { // 回调函数,返回请求的结果
                        // 执行保存的函数,这里我的后端返回的 data 就是 token
                        axiosConfig.saveToken(
                            axiosConfig.tokenLocalKey,
                            data,
                            axiosConfig.tokenLocalSaveTime
                        );
                        // 设置请求头内容(更新请求头的token信息)
                        config.headers.Authorization = data ? data : '';
                        // 处理返回结果
                        // 这里我的逻辑是不需要处理,直接执行 resolve 就行了
                        resolve(data);
                    },
                    '请求方法'
                );
            });
            // 等待鉴权完成返回结果
            await authentication;
            // 重新发起请求
            // 如果一直鉴权失败,并且token获取失败就会一直请求,
            // 这里还有可优化空间,比如:设置重发请求失败错误限制次数、
            // 重发等待时间等等,我就写的简单一点,你们自己升级优化啦
            return axios(config);
        }
        return resp;
    },
    (err) => {
        // 控制台打印错误
        console.log(err);
        // 使用组件提示错误内容
        ElMessage({
            message: `响应时出错: ${err} !`,
            type: 'error',
            showClose: true,
            center: true
        });
    }
);

结语

希望对你能有所帮助,有问题可以私信或下方留言给我