王尘宇王尘宇

研究百度干SEO做推广变成一个被互联网搞的人

Token过期处理

我多次请求用户信息,就会回到登录页面

通过浏览器的开发者工具观察,有两次的刷新Token请求,由于两次的刷新token携带的refresh_token相同,会导致一次成功一次失败,失败的那一次会导致页面跳转请求页

为了避免多次请求刷新Token,可以通过一个变量isRefreshing标记Token的刷新状态

  • 默认状态为false,并且在发送刷新Token请求前检测,状态是false才能发送
  • 发送刷新请求的时候,设置标记为true
  • 请求完毕,设置为false
// layout/components/app-header.vue
...
// 是否正在更新 Token
let isRefreshing = false

request.interceptors.response.use(function (response) {
...
  } else if (status === 401) {
    if (!store.state.user) {...}
    // 发送刷新请求前判断 isRefreshing 是否存在其他已发送的刷新请求
    // 1 如果有,则将当前请求挂起,等到 Token 刷新完毕再重发,这里先设置为 return
    if (isRefreshing) {
      return
    }
    // 2. 如果没有,则更新 isRefreshing 并发送请求,继续执行后续操作
    isRefreshing = true
    // 发送刷新请求
    return request({
     ...
    }).then(res => {
      ...
    }).catch(() => {
      ...
    }).finally(() => {
      // 3 请求完毕,无论成功失败,设置 isRefreshing 为 false
      isRefreshing = false
    })
  } else if (status === 403) {
...

虽然刷新Token的题解决了,但是之前发送的两个请求只有一个成功执行,其他的请求都被阻止了
如何解决?
我们声明一个数组存储所有被挂起的请求,当Token刷新完毕再将这些请求重新发送

// 存储是否正在更新token 的状态
let isRefreshing = false
// 存储因为token刷新而挂起的请求
let requests = []
// 响应拦截器
request.interceptors.response.use(function (response) {
  // 状态码2xx会执行这里
  console.log('响应成功了', response)
  return response
}, function (error) {
  if (error.response) {
    // 请求发送成功,响应接收完毕,但是状态码为失败的情况
    // 1.判断失败的状态码情况(主要处理401的情况)
    const { status } = error.response
    let errorMessage = ''
    if (status === 400) {
      errorMessage = '请求参数错误'
    } else if (status === 401) {
      // 2.Token无效(过期)处理
      // 第一,无token信息
      if (!store.state.user) {
        redirectLogin()
        return Promise.reject(error)
      }
      // 检测是否已经存在了正在刷新token的请求
      if (isRefreshing) {
        // 将当前失败的请求存起来,存储到请求列表中
        return requests.push(() => {
          // 当前函数调用后,会自动发送本次失败请求
          request(error.config)
        })
      }
      isRefreshing = true
      // 第二,Token无效(错误Token,过期Token)
      // 发送请求,获取新的access_token
      return request({
        method: 'POST',
        url: '/front/user/refresh_token',
        data: qs.stringify({
          refreshtoken: store.state.user.refresh_token
        })
      }).then(res => {
        // -刷新token失败
        if (res.data.state !== 1) {
          // 清除无效的用户信息
          store.commit('setUser', null)
          // 封装重复的跳转登录操作
          redirectLogin()
          return Promise.reject(error)
        }
        // 刷新token成功
        // 存储新的token
        store.commit('setUser', res.data.content)
        // 重新发送失败的请求
        // 根据reques
        // 发送多次失败的请求
        requests.forEach(callback => callback())
        // 发送完毕清除requests 内容即可
        requests = []
        // 将本次请求发送
        return request(error.config)
      }).catch(err => {
        console.log(err)
      }).finally(() => {
        // 无论成功还是失败都会执行
        // 请求发送完毕,响应处理完毕,刷新状态更改为false就行了
        isRefreshing = false
      })

解决

相关文章

评论列表

发表评论:
验证码

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。