JS Token无痛刷新

前言

最近在开发后天管理系统时增加了一个token失效以后不返登录页面而是在当前页面用旧的token去服务器换新的token,成功后拿到新的token去发被挂起的请求。这样对于我这样的前端没接触过完全是个坑啊,废话不多说开始正文。

我先贴出代码

/*token失效请求次数*/
window.error = false
/*被挂起的请求数组*/
let refreshSubscribers = [];

/*push所有请求到数组中*/
function subscribeTokenRefresh(cb) {
  refreshSubscribers.push(cb);
}

/*刷新请求(refreshSubscribers数组中的请求得到新的token之后会自执行,用新的token去请求数据)*/
function onRrefreshed(token) {
  refreshSubscribers.map(cb => cb(token));
}
// 响应拦截器
service.interceptors.response.use(
  response => {
    if (response.headers["content-disposition"]) {
      return response;
    }
    if (response.data.code == 200) {
      return response.data;
    } else if(response.data.code == 4001{
        return reloadMessage(response.config)
     }else {
        /* 4001 短token过期 error防止多个网络请求同事报错 */
        if(!window.error){
          window.error = true
          vm.$warning({title: `登录失效,请重新登录`});
          Vue.ls.set('isLogin', false)
          Vue.ls.remove('userInfo')
          window.router.push("/login");
        }
}

/* 消息重发 */
function reloadMessage(config){
    refreshToken().then(res =>{
        var tempdate = new Date().format('Y.MM.dd h:m:s')
        console.log(`更token时间${tempdate};\n新的toke${res.result.token}`)
        /*成功刷新token*/
        config.headers['Authorization'] = res.result.token
        /*更新本地的token*/
        Vue.ls.set('authorization',res.result.token)
        Vue.ls.set('refreshToken',res.result.RefreshToken)
        /*执行数组里的函数,重新发起被挂起的请求*/
        onRrefreshed(res.result.token)
        /*执行onRefreshed函数后清空数组中保存的请求*/
        refreshSubscribers = []
    })
    /*将请求挂起*/
   let retry = new Promise((resolve, reject) => {
      /*(token) => {...}这个函数就是回调函数*/
      subscribeTokenRefresh(token => {
        console.log("重发token is", token.substr(-4));
        config.headers["Authorization"] = token;
        axios.request(config).then(res =>{
            window.requestCount = 0
            resolve(res.data)
        })
      });
    });
    return retry;
}
在开始之前我们应该先知道几个问题?

1.token刷新应该是在js的响应拦截器里做的
2.至于应该是请求发送前判断token失效,还是在token已经失效的时候发送刷新token的请求。其实我感觉在token失效的时候做这个操作是挺好的一种方式,因为你不知道用户可能隔了多长时间去做这个操作,如果隔的时间比较久,这个时候可能就不是很适合继续去刷新token而是返回登录页面。因为这样也许会安全和更合适一些。

1.首先先声明数组,用来挂起的网络请求;如果有网络请求token过期的话就把这个网络请求放到数组里。(这里比较惭愧在学习js的时候竟然不知道可以把数组里面放入请求,当时在网上看到这个骚操作内心一万个曹尼玛飞奔而过)

/*被挂起的请求数组*/
let refreshSubscribers = [];
/*push所有请求到数组中*/
function subscribeTokenRefresh(cb) {
  refreshSubscribers.push(cb);
}
 /*将请求挂起*/
let retry = new Promise((resolve, reject) => {
      /*(token) => {...}这个函数就是回调函数*/
      subscribeTokenRefresh(token => {
        console.log("重发token is", token.substr(-4));
        config.headers["Authorization"] = token;
        axios.request(config).then(res =>{
            resolve(res.data)
        })
      });
  });
 return retry;

2.然后呢就是发送更新token的操作了,换取成功后会更新LocalStorage里的token

/* 消息重发 */
function reloadMessage(config){
    refreshToken().then(res =>{
        var tempdate = new Date().format('Y.MM.dd h:m:s')
        console.log(`更token时间${tempdate};\n新的toke${res.result.token}`)
        /*成功刷新token*/
        config.headers['Authorization'] = res.result.token
        /*更新本地的token*/
        Vue.ls.set('authorization',res.result.token)
        Vue.ls.set('refreshToken',res.result.RefreshToken)
        /*执行数组里的函数,重新发起被挂起的请求*/
        onRrefreshed(res.result.token)
        /*执行onRefreshed函数后清空数组中保存的请求*/
        refreshSubscribers = []
    })
    /*将请求挂起*/
   let retry = new Promise((resolve, reject) => {
      /*(token) => {...}这个函数就是回调函数*/
      subscribeTokenRefresh(token => {
        console.log("重发token is", token.substr(-4));
        config.headers["Authorization"] = token;
        axios.request(config).then(res =>{
            window.requestCount = 0
            resolve(res.data)
        })
      });
    });
    return retry;
}

其中refreshToken()这个方法就是用老的token换取新的token,因为token存在LocalStorage里面所以直接拼到了地址后面,如果失败了就直接返回登录页面;token请求成功后,接下来就是把本地的token替换掉然后发送被挂起的网络请求onRrefreshed(res.result.token)然后subscribeTokenRefresh里面的异步回调。至此整个流程就已经完成了

虽然这只是一个很小的需求,但很考验开发者javascript的知识深度。感谢阅读

你可能感兴趣的:(JS Token无痛刷新)