axios的请求中断和请求重试

请求中断

场景:
	1、假如一个页面接口太多、或者当前网络太卡顿、这个时候跳往其他路由,
	当前页面可以做的就是把请求中断掉(优化)
	2、假如当前接口调取了第一页数据,又调去了第二页的数据,
	当我们调取第二页数据时就需要把第一页数据的请求中断掉
	(常见于在搜索大数据)
	3、取消下载
原理:
	AbortController 接口表示一个控制器对象,允许你根据需要中止一个或多个 Web 请求
技术:axios+vue3.0模拟

AbortController

  1. 实现

    	1、将中止控制器传递给 axios 的 调去接口的方法controller = new AbortController()
    	2、axios里面有定义标识的属性signal
    	3、点击事件:controller.abort()
    
    js 复制代码
    <script setup lang="ts">
    import axios from 'axios'
    import { ref } from 'vue'
    
    const progress = ref(0) // 进度条百分比
    let controller: AbortController // 中止控制器
    
    // 中止下载
    const abortDownload = () => {
      if (controller) {
        controller.abort() // 使用 abort 方法中止下载
        console.log('中止下载')
      }
    }
    
    // 下载视频
    const fetchVideo = () => {
      controller = new AbortController() // 创建 AbortController
      axios({
        // 将中止控制器传递给 axios 的 get 方法
        method: 'GET',
        url: 'http://localhost:3000/video',
        signal: controller.signal,
        responseType: 'arraybuffer',
        onDownloadProgress: (progressEvent) => {
          // 计算进度百分比
          progress.value = Math.round((progressEvent.loaded / progressEvent.total!) * 100)
        }
      })
        .then((response) => {
          console.log('下载完成', response)
          // ✅ 保存下载的文件
          const { buffer } = new Uint8Array(response.data)
          const blob = new Blob([buffer], { type: 'application/octet-stream' })
          const link = document.createElement('a') // 创建链接元素
          link.href = URL.createObjectURL(blob) // 将 Blob 对象转换为 URL
          link.download = 'video.mp4' // 设置文件名
          link.click() // 模拟点击链接元素
        })
        .catch((err) => {
          if (axios.isCancel(err)) {
            console.log('下载被取消')
          } else if (err.name === 'AbortError') {
            console.log('下载被中止')
          } else {
            console.error(`下载错误:${err.message}`)
          }
        })
    }
    </script>
    
    <template>
      <div>
        <button class="download" @click="fetchVideo">下载视频</button>
        <button class="abort" @click="abortDownload">中止下载</button>
        <div class="progress-bar">
          <div class="progress" :style="{ width: progress + '%' }"></div>
          {{ progress }}%
        </div>
      </div>
    </template>
    
    <style scoped>
    .progress-bar {
      height: 20px;
      background-color: #eee;
      margin-top: 10px;
    }
    .progress {
      width: 0%;
      height: 100%;
      background-color: #4caf50;
      transition: width 0.2s linear;
    }
    </style>

请求重试

场景:
	当用户访问我们的 Web 应用程序时,HTTP 请求可能会由于网络不稳定而失败,例如超时或网络异常。

模拟 axios timeout: 2000,服务端加个延时3s。
axios里面设置两个参数:{
	retries: 3, // 设置重试次数为3次
  	retryDelay: 1000, // 设置重试的间隔时间
}
在响应拦截返回失败时进行重试:设置重试次数的参数,再次发送请求

使用 Axios 的拦截器拦截响应,则尝试再次发送请求,通过设置 retry 和 retryDelay 来控制重试请求的数量和每个请求之间的间隔。

```js
<script setup lang="ts">
import axios from 'axios'

const request = axios.create({
  baseURL: 'http://localhost:3000',
  // 设置请求超时时间为5秒
  timeout: 2000,
  retries: 3, // 设置重试次数为3次
  retryDelay: 1000, // 设置重试的间隔时间
} as any)

// 添加响应拦截器
request.interceptors.response.use(
  (response) => {
    // 对响应数据做些什么
    return Promise.resolve(response.data)
  },
  (error) => {
    const config = error.config

    // 如果config不存在或未设置重试选项,则拒绝
    if (!config || !config.retries) {
      return Promise.reject(error)
    }

    // 设置变量来跟踪重试次数
    config.__retryCount = config.__retryCount || 0

    // 检查是否达到最大重试次数
    if (config.__retryCount >= config.retries) {
      return Promise.reject(error)
    }

    // 增加重试计数器
    config.__retryCount += 1

    // 创建一个新的Promise来处理每次重试之前等待一段时间
    const backoff = new Promise((resolve) => {
      setTimeout(() => {
        resolve('重新请求:' + config.__retryCount)
      }, config.retryDelay || 1)
    })

    // 返回Promise,以便Axios知道我们已经处理了错误
    return backoff.then((txt) => {
      console.log(txt)
      return request(config)
    })
  },
)

// 请求中止控制器
let controller: AbortController
// --- 获取数据 ---
const getData = async () => {
  controller = new AbortController()
  const res = await request({
    signal: controller.signal, // 添加请求中止标识
    method: 'GET',
    url: '/delay_3s_data',
  })
  console.log('成功获取数据', res)
}

const stop = () => {
  // 中止网络请求
  controller.abort()
}
</script>

<template>
  <h1>axios请求重试</h1>
  <button @click="getData()">发送请求</button>
  <button @click="stop()">中止请求</button>
</template>

axios-retry 插件

	插件可以更方便实现请求重试
	npm install axios-retry

导入以下数据就可以了
// axios-retry 插件
axiosRetry(request, {
  retries: 3, // 设置重试次数
  retryDelay: () => 500, // 设置重试延迟时间
  shouldResetTimeout: true, // 重置请求超时时间
  // error.code===ECONNABORTED表示请求超时了 ERR_NETWORK网络出错
  retryCondition: (error) => ['ECONNABORTED', 'ERR_NETWORK'].includes(error.code!), // 重试条件
})
js 复制代码
<script setup lang="ts">
import axios from 'axios'
import axiosRetry from 'axios-retry'

const request = axios.create({
  baseURL: 'http://localhost:3000',
  timeout: 2000,
})

// axios-retry 插件
axiosRetry(request, {
  retries: 3, // 设置重试次数
  retryDelay: () => 500, // 设置重试延迟时间
  shouldResetTimeout: true, // 重置请求超时时间
  retryCondition: (error) => ['ECONNABORTED', 'ERR_NETWORK'].includes(error.code!), // 重试条件
})

// 请求中止控制器
let controller: AbortController
// --- 获取数据 ---
const getData = async () => {
  // 请求控制器
  controller = new AbortController()
  const res = await request({
    method: 'GET',
    url: '/delay_3s_data',
    signal: controller.signal, // 添加请求中止标识
  })
  console.log('成功获取数据', res)
}

const stop = () => {
  // 中止网络请求
  controller.abort()
}
</script>

<template>
  <h1>axios请求重试-axiosRetry</h1>
  <button @click="getData()">发送请求</button>
  <button @click="stop()">中止请求</button>
</template>

推荐阅读

axios的issues
掘金-Axios 项目有哪些值得借鉴的地方

相关推荐
cwj&xyp17 分钟前
Python(二)str、list、tuple、dict、set
前端·python·算法
dlnu201525062219 分钟前
ssr实现方案
前端·javascript·ssr
古木201923 分钟前
前端面试宝典
前端·面试·职场和发展
轻口味2 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王2 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发3 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀3 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪3 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef5 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端