原理图


// 添加请求拦截器
request.interceptors.request.use(
  function (config) {
    // 在发送请求之前做些什么
    const token = getToken().token
    if (token) {
      config.headers!.Authorization = `Bearer ${token}`
    }
    return config
  },
  function (error) {
    // 对请求错误做些什么
    return Promise.reject(error)
  }
)

// 添加响应拦截器
request.interceptors.response.use(
  function (response) {
    // 对响应数据做点什么
    return response
  },
  async function (error: AxiosError<{ message: string }>) {
    console.dir(error, '99999')
    // 无感刷新回答:
    //  后台返回401,
    //  响应拦截器中处理 => 判断是否是有token
    //  如果有 说明token过期了 => 尝试用refresh_token 发请求刷新token
    //  刷新成功, 保存到本地以及仓库中 并重新发请求
    //  刷新失败, 说明refresh_token 也过期了 则跳转到登录页

    // 理解 :用户发起一个请求,
    // 情况1:请求成功正常拿到数据,正常渲染
    // 情况2: 没有返回结果 说明服务器有误,提示用户
    // 情况3: 后端返回401 说明token过期,请求拦截器中判断返回结果是否为401,
    // 如果是401则,尝试利用refresh_token发送一个刷新token请求
    // 拿回新token 基于新的token在发送上一个响应错误的请求,
    // 如果没有拿到新的token 则说明refresh_token也过期,跳转登录页
    // 如果本地根本没有token,请直接拦截到登录页

    
    // 对响应错误做点什么
    // !----------------情况1:服务器繁忙------------
    if (!error.response) {
      // 如果没有响应信息
      Toast.show({
        content: '服务器繁忙,请稍后重试',
        duration: 3000,
      })
      return Promise.reject(error)
    }
    // !----------------情况2:token过期----------------
    const token = getToken()
    // 判断是否为401
    if (error.response.status === 401) {
      // 是的话判断本地有没有refresh_token
      // 如果有token 发送请求获取新的token
      if (token.refresh_token) {
        try {
          // 获取新的token
          const res = await axios({
            method: 'put',
            url: baseURL + '/authorizations',
            headers: {
              Authorization: 'Bearer ' + token.refresh_token,
            },
          })
          // 拿到新token 存入仓库
          store.dispatch(
            savetoken({
              // token为最新获取的token
              token: res.data.data.token,
              // refresh_token是从本地获取的
              refresh_token: token.refresh_token,
            })
          )
          // 存入成功后 重新发送错误请求
          return request.request(error.config)
        } catch (error) {
          // !----------------情况3:refresh_token过期----------------
          // 如果失败说明 refresh_token也过期 重新登录
          Toast.show({
            content: '登录信息过期,请重新登录',
          })
          // 清除现有的所有的token
          store.dispatch(LogOut())
          // 携带当前路径 直接跳转
          history.replace({
            pathname: '/login',
            state: {
              form: history.location.pathname,
            },
          })
        }
        return Promise.reject(error)
      } else {
        // !----------------情况4:根本没有token----------------
        // 如果没有直接跳
        Toast.show({
          content: '登录认证失效',
        })
        // 携带当前路径 直接跳转
        history.replace({
          pathname: '/login',
          state: {
            form: history.location.pathname,
          },
        })
        return Promise.reject(error)
      }
    }

    // 提示用户错误信息
    Toast.show({
      content: error.response?.data.message,
      duration: 3000,
    })
    return Promise.reject(error)
  }
)
最后修改:2022 年 05 月 02 日
END
本文作者:
文章标题:React、Vue项目中Token无感刷新原理-实用大多数项目
本文地址:https://zhougewk8.cn/11.html
版权说明:若无注明,本文皆Dg's Blog-专注健康快乐每一天原创,转载请保留文章出处。
如果觉得我的文章对你有用,请随意赞赏