前端token无感刷新

前端登录业务中,现在比较常用的是后端返回长短有效期的双token,在我们短token的过期后,使用r长token进行更新短token操作,但是又不想中断用户操作,这个时候就需要调整axios进行token的无感刷新。
根据上述操作我们需要以下步骤:

  1. 当请求返回token过期的状态码时拦截用户请求
  2. 拿到长token发起刷新token操作的请求
  3. 拿到刷新token请求的结果
  4. 根据结果进行下一步操作:跳转到登录还是恢复调用用户请求

具体的代码实现如下:

const getToken = () => {
  const token = localStorage.getItem("token")
  if (token) {
    return token
  }
  return ''
}
const requset = axios.create({
  baseURL: "/api",
  timeout: 5000,
});
// 请求拦截
requset.interceptors.request.use((config) => {
  const token = getToken()
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

// 响应拦截
requset.interceptors.response.use(async (res) => {
  // 2xx 状态码会执行这里
  if (res.status >= 200 && res.status < 300) {
    return res.data
  }
}, async (err) => {
  // 非正常状态
  if (err.status == 401) {
    console.log("未登录")
    // location.href = "/login"
  } else if (err.status == 403) {
    // 刷新token
    const res = await refreshTokenApi()
    // 判断刷新token的结果
    if (res) {
      // 重新发送请求
      err.config.headers.Authorization = `Bearer ${getToken()}`
      // 等待重新请求结果
      const response = await requset.request(err.config)
      // 返回重新请求结果
      return response
    } else {
      console.log("刷新token失败")
      // location.href = "/login"
      return err
    }
  }
  return Promise.reject(err)
})
export default requset

refreshTokenApi的实现如下:
代码中promise作用是当连续并发多个请求都过期时 只返回一个刷新token的promise, 否则会发起多个请求,造成刷新的token过期陷入死循环

let promise; 
const refreshTokenApi = () => {
  if (promise) {
    return promise
  }
  promise = new Promise(async (resolve, reject) => {
    // 拿到长token
    const token = localStorage.getItem("refresh")
   // 未取到长token 直接返回失败
    if (!token) {
      return false
    }
    // 换取新的token
    const res = await request({
      url: "/refresh",
      method: "post",
      data: { refreshToken: token }
    })
    localStorage.setItem("token", res.data.token)
    localStorage.setItem("refresh", res.data.refreshToken)
   // 返回token刷新的结果 这里需要根据项目实际返回值确定
    resolve(res.code == 1)
  })
  // 刷新完成后 清空promise
  promise.finally(() => {
    promise = null
  })
  return promise
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容