- 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>
- 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,
},
});
});