Axios

Aug 25 · 3min

请求失败自动重新请求

方案1

手动实现一个简易的请求失败

基本流程
image-20240902222824361
源代码

配置基本项

// 最大重试次数
const MAX_RETRIES = 3 
// 重试时间间隔
const RETRY_DELAY = 1000

重试的请求函数

instance(config)发送请求

const backoff = new Promise((resolve) => {
    setTimeout(() => {
      resolve(instance(config))
    // RETRY_DELAY 每次请求的时间间隔
    }, RETRY_DELAY)
})

所有代码

import axios from 'axios'
import { jwtDecode } from 'jwt-decode'
import { getUserStore } from '@/stores'
const userStore = getUserStore()
const instance = axios.create({
  baseURL: 'http://localhost:3000'
})
const MAX_RETRIES = 3
const RETRY_DELAY = 1000

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

// 添加响应拦截器
instance.interceptors.response.use(
  (response) => {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    if (response.data.code && response.data.code === 2000) {
      return Promise.reject(response)
    }
    return response
  },
  async (error) => {
    const config = error.config
    if (!config.retryCount) {
      config.retryCount = 0
    }
    if (config.retryCount < MAX_RETRIES) {
      config.retryCount++
      console.log('retryCount', config.retryCount)
      const backoff = new Promise((resolve) => {
        setTimeout(() => {
          resolve(instance(config))
        }, RETRY_DELAY)
      })
      await backoff
    }
    if (error?.response?.status === 401) {
      // 清空token
      userStore.setToken('')
      ElMessage.error('登陆过期')
    }
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    return Promise.reject(error)
  }
)

export default instance

方案2

通过库axios-retry来实现

官方文档

pnpm install axios-retry

取消请求

官方文档教程

流程图

image-20240903113304977

基本步骤

  • 通过axios.CancelToken.source()方法生成source

  • 给请求添加配置项cancelToken,值为source.token,此时的请求相当于和source绑定

  • 通过source.cancel('取消请求的原因')取消请求

    注意:

    1.想取消哪个请求就必须调用哪个请求的source.cancel()方法

    2.每个请求的cancelToken的位置不一样(具体看文档)

    • get

      axios.get('xxx', {
        cancelToken: source.token
      })
    • post

      axios.post('xxx', {
        name:'xxx'
      },{
        ancelToken: source.token
      })
    • put

      axios.put('xxx', {
        name:'xxx'
      },{
        ancelToken: source.token
      })
    • delete

      axios.delete('xxx', {
        cancelToken: source.token
      })

代码(get请求)

  • 接口函数
import http from '@/utils/http'
const getMovieService = async (params, cancelToken) => {
// http为axios实例
  return http.get('/getMovie', {
    params,
    ...(cancelToken ? { cancelToken } : {})
  })
}
  • 简单使用

    模拟搜索,当用户多次点击搜索按钮,如果之前搜索的请求还没有请求成功,则取消上次的搜索

    // 导入接口函数
    import { getMovieService } from '@/api/movie'
    import axios from 'axios'
    
    // 考虑到可能有多个不同的请求,因此使用key-value的形式来储存请求的source
    // key->'哪个请求'  value->'source'
    const cancelTokens = {
      getTableDataRequest: null
    }
    
    const handleSearch = async () => {
      // getTableDataRequest有值,之前发送过一次请求
      if (cancelTokens.getTableDataRequest) {
        cancelTokens.getTableDataRequest.cancel('取消请求')
      }
      const movieName = inputValue.value
      const { pageSize, currentPage } = baseTableComRef.value.getPaginationData()
      const pageIndex = currentPage
      // 创建source
      const source = axios.CancelToken.source()
      // 储存改请求的source
      cancelTokens.getTableDataRequest = source
      // source.token作为cancelToken传入函数
      getTableData({ pageSize, pageIndex, movieName }, source.token)
    }
    
    // 把接口函数getMovieService重新封装了一次
    const getTableData = async (params, cancelToken) => {
      await getMovieService(params, cancelToken)
        .then((res) => {
         cancelTokens.getTableDataRequest = null
      }).catch((err) => {
          console.log('err', err)
        })
    }
CC BY-NC-SA 4.0 2024-PRESENT © hujiacheng