devStandard/docs/learning/5-vue/3.1-axios取消请求.md
2025-03-29 14:35:49 +08:00

5.1 KiB
Executable File
Raw Permalink Blame History

Axios取消请求

原生js的abort()取消ajax请求

<div class="page" id="app">
    <button  class="get-msg">获取数据</button>
    <button  class="cancel">取消获取</button>
  </div>
<script>
  var currentAjax = null
    $('.get-msg').click(function () {
      currentAjax = $.ajax({
        type: 'GET',
        url: 'http://jsonplaceholder.typicode.com/comments',
        success: function (res) {
          console.log(res)
        },
        error: function (err) {
          console.log("获取失败")
        }
      })
    })
    $('.cancel').click(function () {
      if (currentAjax) {
        currentAjax.abort()
      }
    })
  </script>

在axios中取消接口请求操作

Axios 提供了一个 CancelToken的函数这是一个构造函数该函数的作用就是用来取消接口请求

官方文档:

方法一:

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  // 必须对请求进行cancelToken设置
  cancelToken: source.token
}).catch(function (thrown) {
  // 如果请求被取消则进入该方法判断
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

// 取消上面的请求
// source.cancel('messge') message为可选项必须为String
source.cancel('Operation canceled by the user.');

方法二:

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  // 在options中直接创建一个cancelToken对象
  cancelToken: new CancelToken(function executor(c) {
    cancel = c;
  })
});

// 取消上面的请求
cancel();

实例:

<!DOCTYPE html>
<html lang="zh-cn">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.24.0/axios.js"></script>
  </head>
  <body>
    <div class="page" id="app">
      <button @click="getMsg" class="get-msg">获取数据</button>
      <button @click="cancelGetMsg" class="cancel">取消获取</button>
      <ul>
        <li v-for="item in items">{{item.name}}</li>
      </ul>
    </div>
    <script>
    var app = new Vue({
      el: '#app',
      data: {
        message: 'Hello Vue!',
        items: [],
        cancel: null
      },
      methods: {
        getMsg () {
          let CancelToken = axios.CancelToken
          let self = this
          axios.get('http://jsonplaceholder.typicode.com/comments', 
            {
              cancelToken: new axios.CancelToken(function executor(c) {
                self.cancel = c
                // 这个参数 c 就是CancelToken构造函数里面自带的取消请求的函数这里把该函数当参数用
              })
            }
            ).then(res => {
            this.items = res.data
          }).catch(err => {
            console.log(err)
          })
        },
        // 开发者工具里把网速调成slow 3G
        cancelGetMsg () {
          this.cancel()
        }
      }
    })
    </script>
  </body>
</html>

重复点击造成重复请求的问题

  // 正在进行中的请求列表
let reqList = []

/**
 * 阻止重复请求
 * @param {array} reqList - 请求缓存列表
 * @param {string} url - 当前请求地址
 * @param {function} cancel - 请求中断函数
 * @param {string} errorMessage - 请求中断时需要显示的错误信息
 */
const stopRepeatRequest = function (reqList, url, cancel, errorMessage) {
  const errorMsg = errorMessage || ''
  for (let i = 0; i < reqList.length; i++) {
    if (reqList[i] === url) {
      cancel(errorMsg)
      return
    }
  }
  reqList.push(url)
}

/**
 * 允许某个请求可以继续进行
 * @param {array} reqList 全部请求列表
 * @param {string} url 请求地址
 */
const allowRequest = function (reqList, url) {
  for (let i = 0; i < reqList.length; i++) {
    if (reqList[i] === url) {
      reqList.splice(i, 1)
      break
    }
  }
}

const service = axios.create()

// 请求拦截器
service.interceptors.request.use(
  config => {
	let cancel
  	// 设置cancelToken对象
    config.cancelToken = new axios.CancelToken(function(c) {
    	cancel = c
    })
    // 阻止重复请求。当上个请求未完成时,相同的请求不会进行
    stopRepeatRequest(reqList, config.url, cancel, `${config.url} 请求被中断`)
    return config
  },
  err => Promise.reject(err)
)

// 响应拦截器
service.interceptors.response.use(
  response => {
    // 增加延迟,相同请求不得在短时间内重复发送
    setTimeout(() => {
      allowRequest(reqList, response.config.url)
    }, 1000)
    // ...请求成功后的后续操作
    // successHandler(response)
  },
  error => {
    if (axios.isCancel(thrown)) {
      console.log(thrown.message);
    } else {
      // 增加延迟,相同请求不得在短时间内重复发送
      setTimeout(() => {
        allowRequest(reqList, error.config.url)
      }, 1000)
    }
    // ...请求失败后的后续操作
    // errorHandler(error)
  }
)

[1]. https://www.jianshu.com/p/22b49e6ad819

[2]. https://blog.csdn.net/harsima/article/details/93717217