|
VUE拦截请求并无感知刷新token
应用场景
前端登录后,后端返回token和token失效时间,当达到特定条件(本文以距离token过期两小时为例),前端需要主动请求token刷新接口去获取一个新的token,做到用户无感知地去刷新token。
思路
拦截请求判断是否达到需要刷新token的条件,符合条件则刷新token并将请求存入一个重试队列中,当token刷新后,执行重试队列中的函数,达到刷新token的效果,
需要注意的是,当多个请求几乎同时进来时,为了避免多次执行token刷新,需要定义一个变量(本文变量名为isRefreshing )进行标记。- import axios from "axios";
- import store from "@/store";
- import md5 from "js-md5";
- import {
- setToken,
- getToken,
- setUid,
- setExpireTime,
- getExpireTime
- } from "@/utils/auth";
- // 创建axios实例
- const service = axios.create({
- // axios中请求配置有baseURL选项,表示请求URL公共部分
- baseURL: window.location.protocol + process.env.VUE_APP_BASE_API,
- // 超时
- timeout: 10000
- });
- // 是否正在刷新的标记
- let isRefreshing = false;
- // 重试队列,每一项将是一个待执行的函数形式
- let requests = [];
- // 判断是否距离过期2个小时
- function isRefreshTokenExpired() {
- const expire_time = getExpireTime(); // 到期时间
- const new_time = new Date().getTime(); // 当前时间
- const stamp = expire_time - new_time; // 距离到期时间
- return stamp <= 2 * 60 * 60 * 1000 ? true : false; // 2小时
- }
- // request拦截器
- service.interceptors.request.use(
- config => {
- const tokenObj = getToken();
- if (config.data.method === "xxxx") { //当请求的接口为token刷新接口时
- return config;
- }
- if (tokenObj && isRefreshTokenExpired()) {
- // 立即刷新token
- if (!isRefreshing) {
- isRefreshing = true;
- // 请求token刷新接口
- store
- .dispatch("RefeshToken")
- .then(res => {
- const token = res.data.token;
- const time = res.data.expire_time.replace(/-/g, "/");
- const expire_time = new Date(time);
- setToken(token, expire_time);
- setExpireTime(new Date(res.data.expire_time).getTime(), expire_time);
- setUid(res.data.uid, expire_time);
- isRefreshing = false;
- return token;
- })
- .then(token => {
- requests.forEach(cb => cb(token));
- // 执行完成后,清空队列
- requests = [];
- })
- .catch(res => {
- console.error("refresh token error: ", res);
- });
- }
- const retryOriginalRequest = new Promise(resolve => {
- requests.push(token => {
- // 因为config中的token是旧的,所以刷新token后要将新token传进来
- config.headers["ContentToken"] = token;
- resolve(config);
- });
- });
- return retryOriginalRequest;
- }
- return config;
- },
- error => {
- Promise.reject(error);
- }
- );
- // 响应拦截器
- service.interceptors.response.use(
- res => {
- if (res.status === 200) {
- return res
- }
- },
- error => {
- console.log('catch', error)
- return Promise.reject(error)
- }
- );
- export default service;
复制代码 总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
来源:https://www.jb51.net/javascript/326741v10.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
|