前端多请求携带token过期的处理办法( ̄︶ ̄)↗

9,155 阅读3分钟

前言🎈

在写项目(Vue)的时候遇到一个问题,对于后端返回的token的过期的处理。这个表面来说是个很常见的问题,但是我的问题比较小坑😂

问题❓

前端的项目页面,对于一个页面初始化的时候可能不止一个携带token的请求,假如这几个请求不是相互依赖的,所以可以进行一个并发的请求处理,合理吧🙄。

那么问题来了,请求是一个异步的行为,就算是同时请求,数据的返回也要有个先后,对于第一个返回过来的数据提示我们token已经过期,那么就会触发我们在请求函数封装那边的token过期处理(清除本地缓存token,并把当前失效的地址拼接到登录地址跳转)

例:login?callback=xxxxx

多个请求,所以会触发好几次的响应拦截,并且触发的时机会有先后之分,甚至有可能进入登录页面之后,有的响应才刚从后台返回,这并不是我们所希望看到的,因为会引发很多未知的问题。 image 我现在遇到的情况就是,如果第一个响应返回token失效,那么我这边会做一个拦截的操作,获取当前失效页面的URL地址order?id=1这种地址,跳转到login页面

//我这边把 order?id=1 base64位加密
let path = "/order?id=1"  //vue的路由
path = Base64.encode(path)
let callback=`login?callback=${path}`

那么,跳转到登录页面以后,会有一个响应才从后端返回,那么这个拦截函数又把地址处理了一遍

let path = "/login?callback=xxx" //当前获取到的地址变成了登录页
path = Base64.encode(path)
let callback=`login?callback=${path}`

这种问题就出来了💥

解决方法🔑

第一种方法

在拦截函数上进行一个修改,我用的是axios

axios.interceptors.response.use(response => {
 //对于token过期的处理
 if (response.data.code == 102) {
        let path = location.hash.split("/")[1]
        if (!(/callback/g).test(path)) {
            let code = Base64.encode(path)
            router.replace("/login?callback=" + code)
        }
    }
})

对于地址携带callback字段的URL地址,一律拦截,虽然粗糙但能解决问题😂

第二种方法

针对第一种方法的改进,使用callback字段终归觉得有点问题,查阅axios的文档,有一个阻止请求的配置cancelToken,那么就用它对这个拦截函数进行一个改造

const cancelToken = axios.CancelToken;  //阻止请求
const pendding = []  //把当前请求的状态都存到一个数组里
axios.interceptors.request.use(config => {
    config.cancelToken = new cancelToken((c) => {
        pendding.push({ fun: c, url: config.url })
    })
})
request.interceptors.response.use(response => {
    //对于token过期的处理
    if(response.data.code===200){
        //对于请求ok的数据
        for(let i=0;i<pendding.length;i++){
            if(response.config.url===pendding[i].url){
                pendding.splice(i, 1); //把这条记录从数组中移除
            }
        }
        return response.data
    }
    if(response.data.code===102){
        for(let i=0;i<pendding.length;i++){
             pendding[i].fun(); //执行取消操作
             pendding.splice(i, 1); //把这条记录从数组中移除
        }
        
        let path = location.hash.split("/")[1]
        let code = Base64.encode(path)
        router.replace("/login?callback=" + code)
    }
})

目前整个逻辑

  • 请求拦截方面,对于所有正在请求的api做一个数组存储
  • 响应拦截方面,针对请求200的数据,从请求数组中剔除掉,对于token过期的请求,进行一个对已经发起请求还没返回响应的取消请求操作,并从请求数组中剔除掉。

小结😊

这篇文章针对自己所遇到的问题和当前的解决方案的总结。我相信这并不是最好的解决方法,奈何能力有限只能想到这两种方式。

现在目前还有一个可以优化修改的点,就是请求的同时返回(间隔时间很短),这就导致拦截函数还是会触发不止一次,其实如果第一次返回token失效之后,后面的请求就没必要再发了。针对这个问题,自己所想的就是先发一个预检请求,请求返回token正常,再发其他的请求,目前所想到的最笨的方法😥

created: async (){
    let result = await verifyToken()
    if(result.code===200){
        //其余的请求
    }
}

多多指教,互相学习

参考资料📒