axios无感刷新token

  1. html代码
html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.14/theme-chalk/index.css" rel="stylesheet">
</head>

<body>

    <div>
        <button class="el-button el-button--primary">获取token</button>
        <button class="el-button el-button--primary">测试</button>
        <button class="el-button el-button--primary">刷新</button>
    </div>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.9.0/axios.js"></script>
    <script>
        const getToken = () => {
            return localStorage.getItem('token');
        }
        const setToken = (token) => {
            localStorage.setItem('token', token);
        }

        axios.defaults.baseURL = 'http://localhost:18565';
        axios.interceptors.request.use(config => {
            config.headers.authorization = getToken();
            return config;
        }, error => {
            return Promise.reject(error);
        });

        let isRefreshing = false;
        let queue = [];
        axios.interceptors.response.use(response => {
            return response.data;
        }, error => {
            if ([403, 401].includes(error.status)) {
                if (!isRefreshing) {
                    isRefreshing = true;
                    return axios.request({ url: '/test/api/refresh-token', method: 'post' }).then(res => {
                        setToken(res.data.token);
                        queue.forEach(callback => callback());
                        queue = [];
                        return axios.request(error.config);
                    }).finally(() => {
                        isRefreshing = false;
                    })
                }
                return new Promise((resolve, reject) => {
                    queue.push(() => {
                        axios.request(error.config)
                    });
                });
            }
            return Promise.reject(error);
        });

        const test1 = document.querySelector('.el-button--primary:nth-child(1)');
        const test2 = document.querySelector('.el-button--primary:nth-child(2)');
        const refresh = document.querySelector('.el-button--primary:nth-child(3)');

        test1.addEventListener('click', () => {
            axios.request({
                url: '/test/api/get-token',
                method: 'get',
            }).then(res => {
                localStorage.clear();
                console.log(res.data.token, '---------get-token');
                setToken(res.data.token);
            });
        });

        test2.addEventListener('click', () => {
            axios.request({
                url: '/test/api/protected',
                method: 'get',
                headers: {
                    authorization: getToken()
                }
            }).then(res => {
                console.log(res, '---------protected');
            });
        });

        refresh.addEventListener('click', () => {
            axios.request({
                url: '/test/api/refresh-token',
                method: 'post',
            }).then(res => {
                console.log(res, '---------refresh-token');
            });
        });
    </script>
</body>

</html>
  1. server端代码,可以使用mock进行模拟
js 复制代码
const expireTime = 10 * 1000;
// 生成简单的token字符串
function generateToken() {
    // 生成一个随机字符串作为token
    return (Date.now() + expireTime).toString();
}

// 获取初始token接口
// 前端首次调用此接口获取token
router.get('/api/get-token', (req, res) => {
    const token = generateToken();
    res.json({
        code: 200,
        msg: 'token获取成功',
        data: {
            token,
        },
    });
});

// 受保护的接口,调用次数超过限制就返回token过期
router.get('/api/protected', (req, res) => {
    // 从请求头获取token,前端需在请求头加authorization: token
    const token = req.headers['authorization'];
    let isExpire = parseInt(token) >= Date.now();
    // 检查token是否存在且有效
    if (!token || !isExpire) {
        // 没有token或token无效
        return res.status(401).json({code: 401, msg: 'token已过期,请刷新token'});
    }
    res.json({
        code: 200,
        msg: '调用成功',
        data: {
            msg: '调用成功',
        },
    });
});

// 刷新token接口,返回新token并重置计数
router.post('/api/refresh-token', async (req, res) => {
    await sleep(5 * 1000);
    const newToken = generateToken();
    res.json({
        code: 200,
        msg: 'token刷新成功',
        data: {
            token: newToken,
        },
    });
});
相关推荐
格子软件23 分钟前
2026年GEO优化系统源码解构:核心状态机与高并发流控深度剖析
java·vue.js·spring boot·vue·geo
触底反弹32 分钟前
🔥 字符串算法面试三连击:反转、回文、回文变种,搞懂这三题稳了!
前端·javascript·算法
触底反弹41 分钟前
AI Tool Use 深度解析:大模型是如何"突破物理限制"调用外部工具的?
javascript·人工智能·后端
竹林8181 小时前
从 RPC 超时到批量签名:我用 @solana/web3.js 重构了一个 NFT 铸造页面,踩了这些坑
前端·javascript
工业HMI实战笔记1 小时前
工业HMI界面布局“1核2辅”黄金结构,适配90%场景
前端·ui·性能优化·自动化·交互
橘子星1 小时前
从零手写 RAG 语义检索:基于 Node.js 实现轻量级向量搜索
javascript·人工智能
林希_Rachel_傻希希2 小时前
web性能优化之————图片效果
前端·javascript·面试
橘子星2 小时前
基于 MCP 协议实现本地文件读取工具服务开发实践
javascript·人工智能
Darling噜啦啦2 小时前
前端存储与 this 指向完全指南:从 LocalStorage 实战到 call/apply/bind 深度解析
前端·javascript
sugar__salt2 小时前
手撕字符串算法:反转、回文、验证回文 Ⅱ 完整拆解
javascript·算法·面试·职场和发展