axios利用promise刷新token重试失败接口

项目开发中,我们在请求数据的时候经常会遇到 token 失效,无法请求数据的问题。 遇到这类问题,一般的处理方法就是跳转到登录页面重新登录获取token。如果忽视用户的是用心情,这样处理也未尝不可。
但这并不是我想要的效果。作为一个有理想的前端我们应该有更高的要求。 我期望当接口过期时,重新请求一个有效的token,并使用新token,重试上次失败的请求。

解决思路

本文以 axios 为例,因此我们需要在请求的拦截器 axios.interceptors.response.use() 上做文章。我的后端没有在接口中返回状态码,因此我实在拦截器的 error 的处理函数中做处理

具体思路:

  • 在 axios.interceptors.response.use() 拦截器 error 处理函数中判断状态码 (error.request.status) 是否为 401
  • 如果为 401 记录当前请求的 config = error.config 并且 return 一个请求 updateToken(获取新token的请求)
  • 为了避免 在请求新的 token 过程中有新的请求进来,再次重新请求 token,导致新的 token 失效,我们需要一个标记变量来锁定,确保不会多次请求新的 token 造成影响。
  • 设定一个队列,将开始更新 token 开始之后,完成之前的所有请求以一个待执行的函数形式存放在其中
  • 在 updateToken 的回调函数中更新缓存的 token, 并将即将重试的config中的token 更新, 同时 为了避免缓存的影响,将请求的地址 增加一个时间戳参数
  • 启用队列中待重试函数,启用完成后队列置空。 重试当前 config 实例

项目中的token是存在localStorage中的。request.js基本结果:如下

/**
 * 方法说明,
 * setToken() 在 localStorage 中存 token 的方法
 * getToken() 获取 localStorage 中 token 的方法
 * removeToken() 清除 localStorage 中 token 的方法
 * updateToken()  获取新的 token 的请求
 *  */
 
// 1.声明实例
const service = axios.create({
  timeout: 50000 // request timeout
})
// 是否正在刷新的标记
let isRefreshing = false
// 重试队列
let requests = []

service.interceptors.response.use(
  (response) => {   
    return response 
  },
  (error) => {
    if (error.request.status === 401) {
      // 记录实例
      const config = error.config
      // 判断是否正在更新 token 
      if(!isRefreshing) {
      // 改变标记状态
        isRefreshing = true
        // 请求 token 的函数前一定要 return 否则重试成功的数据,
        // 不会返回到请求数据函数的 response 中
        return updateToken().then(res => {
          setToken(res.data.access_token)
          // 重试队列中存储请求
          requests.forEach(cb => cb())
          // 清空队列
          requests = []
          return service(config)
        }).catch(()=> {
        	// 请求新的 token 失败 跳转登录页
        }).finally(() => {
        	// 请求回 token 处理完成 一定要改变标记状态 否则会一直重新请求 token 
          isRefreshing = false
        })
      } else {
        return new Promise((resolve) => {
          // 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行
          requests.push(() => {
          // // 给url 增加时间戳 避免请求缓存影响
            if( config.url.indexOf('?') > -1) {
              config.url = config.url + '&n='+ new Date().getTime()
            } else  {
              config.url = config.url + '?n='+ new Date().getTime()
            }
            config.headers['Authorization'] = getToken()
            resolve(service(config))
          })
        })
      } 
    } else {
      return Promise.reject(error)
    }
  })
export default service

本文实现参考: axios如何利用promise无痛刷新token

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用axios发送请求时,我们可以通过Promise无痛刷新token,确保在token过期之后,通过刷新token的方式继续发送请求。 以下是实现该功能的一种方式: 首先,我们需要创建一个axios实例,并设置请求拦截器。在请求拦截器中,我们通过判断是否存在有效的token来决定是否需要刷新token。 ```javascript import axios from 'axios'; // 创建axios实例 const instance = axios.create(); // 设置请求拦截器 instance.interceptors.request.use( (config) => { // 将token添加到请求头 const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => { return Promise.reject(error); } ); ``` 接下来,我们需要在响应拦截器中处理token刷新的逻辑。当接收到后端的响应时,我们可以在响应拦截器中判断是否返回了一个特定的错误码,表示token已过期。如果是,则我们需要使用refreshToken刷新token。 ```javascript // 设置响应拦截器 instance.interceptors.response.use( (response) => { // 处理响应数据 return response; }, (error) => { // 判断是否为token过期的错误码 if (error.response && error.response.status === 401) { const originalRequest = error.config; // 使用refreshToken刷新token return refreshToken().then((newToken) => { // 刷新成功后将新token保存到本地存储 localStorage.setItem('token', newToken); // 重新发送原始请求 originalRequest.headers.Authorization = `Bearer ${newToken}`; return axios(originalRequest); }).catch((refreshError) => { // 刷新失败处理逻辑,跳转到登录页面等 console.error('刷新token失败:', refreshError); // 重定向到登录页面等 window.location.href = '/login'; return Promise.reject(refreshError); }); } return Promise.reject(error); } ); ``` 在上面的代码中,refreshToken函数用于实现刷新token的逻辑。它可以发送一个特殊的刷新token请求,并返回新的token。在刷新成功后,我们将新的token保存到本地存储中,并重新发送原始请求。 需要注意的是,如果刷新token失败,我们需要根据具体业务需求进行相应的处理,例如跳转到登录页面,弹窗提示重新登录等。 最后,我们可以使用该axios实例来发送请求,它会自动判断是否需要刷新token,并且无需手动处理token过期的情况。 希望以上回答能对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值