美文网首页
JS Token无痛刷新

JS Token无痛刷新

作者: 牧羊人Q | 来源:发表于2019-04-25 17:24 被阅读0次

    前言

    最近在开发后天管理系统时增加了一个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无痛刷新

          本文链接:https://www.haomeiwen.com/subject/msjbiqtx.html