axios封装刷新Token优化(统一登陆)

539 阅读1分钟

业务场景

前提:统一登录sso,双token:token,rToken

token过期时多次发出刷新Token请求,导致服务资源的浪费,所以我们需要添加一个标识isRefreshToken
解决多次刷新的问题后,发现刷新等待期间发出的请求仍然用的之前的Token导致报错,所以这里需要一个存储请求的数组refreshRequest

  • request.js
// 请求前拦截(根据各个系统不同,请求头不同)
service.interceptors.request.use(
  (config) => {
    config.headers['Authorization'] = getToken()
    config.headers['P-Rtoken'] = getRToken()
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)
let isRefreshToken=false //是否正在刷新Token【防止多次刷新浪费资源】
let refreshRequest=[]  // 缓存请求队列【解决刷新期间发出的请求任然报错问题】
// 返回结果前拦截
service.interceptors.response.use((response) => {
  const res = response.data
  // 如果后端返回状态码是Token已过期的状态码
  if (isTokenExpired(Number(res.code))) {
     // 刷新token
     if(!isRefreshToken){
       isRefreshToken=true
      return store.dispatch('user/refreshToken').then(({ data }) => {
         if (data.token) {
           setToken(data.token, data.rtoken)
           // 更新请求头
           const params = response.config.params
           if (params && params.token) params.token = data.token
           refreshRequest.forEach(callback=>{
             callback(data.token)
           })
           return service(response.config)
         } else {
           // 刷新失败需要重新登录 
           toLogin()
           return Promise.reject()
         }
       }).catch(toLogin).finally(()=>{
         isRefreshToken=false
       })
     }else{
        // 缓存请求列表(利用Promise防止之前的请求返回错误的Token导致的错误信息)
        return new Promise((resolve) => {
         // 将resolve放进队列,等token刷新后直接执行
         refreshRequest.push((token) => {
           // 更新请求头
           response.config.headers['Authorization'] = token
           resolve(service(response.config));
         });
       });
     } 
  }