【问题标题】:how to cancel/abort ajax request in axios如何在 axios 中取消/中止 ajax 请求
【发布时间】:2016-11-14 17:09:34
【问题描述】:

我将axios 用于 ajax 请求,reactJS + flux 用于渲染 UI。在我的应用程序中有第三方时间线(reactJS 组件)。时间线可以通过鼠标滚动来管理。应用程序在任何滚动事件后发送实际数据的 ajax 请求。在服务器上处理请求可能比下一个滚动事件更慢的问题。在这种情况下,应用程序可能有几个(通常是 2-3 个)请求,这些请求已经被弃用,因为用户滚动得更远。这是一个问题,因为每次接收新数据时,时间线都会开始重绘。 (因为是reactJS + Flux)正因为如此,用户多次看到时间轴的来回移动。解决这个问题的最简单方法,就是像jQuery 一样中止之前的ajax 请求。例如:

    $(document).ready(
    var xhr;

    var fn = function(){
        if(xhr && xhr.readyState != 4){
            xhr.abort();
        }
        xhr = $.ajax({
            url: 'ajax/progress.ftl',
            success: function(data) {
                //do something
            }
        });
    };

    var interval = setInterval(fn, 500);
);

如何取消/中止axios中的请求?

【问题讨论】:

标签: reactjs flux reactjs-flux es6-promise axios


【解决方案1】:

Axios 目前不支持取消请求。详情请见this issue

更新:Cancellation support 已添加到 axios v0.15。

编辑:axios 取消令牌 API 基于撤销的可取消承诺提案。

例子:

const cancelTokenSource = axios.CancelToken.source();

axios.get('/user/12345', {
  cancelToken: cancelTokenSource.token
});

// Cancel request
cancelTokenSource.cancel();

【讨论】:

  • @RajabShakirov 更新
  • 请包含一个最小示例,以防链接资源出现故障!
  • 如果你这样做,它就不能再运行了
  • const cancelTokenSource = axios.CancelToken.source(); axios.get('/user/12345', { cancelToken: cancelTokenSource.token }); cancelTokenSource.cancel();
  • 直接来自链接:“axios取消令牌API是基于撤回的可取消承诺提案。”如果我理解正确的话,它是基于一些不是支持,在这种情况下我不想使用它。显然我们有仍然是实验性的abortable fetch(特别是见例子);我很好奇这是如何演变的。另见Can I use AbortController?
【解决方案2】:

有一个非常不错的包,其中包含一些名为 axios-cancel 的使用示例。 我发现它很有帮助。 这是链接:https://www.npmjs.com/package/axios-cancel

【讨论】:

    【解决方案3】:

    这就是我在 node.js 中使用 Promise 的方式。发出第一个请求后轮询停止。

     var axios = require('axios');
        var CancelToken = axios.CancelToken;
        var cancel;
        axios.get('www.url.com',
                          {
                            cancelToken: new CancelToken(
                                function executor(c) {
                                    cancel = c;
                                 })
                          }
                ).then((response) =>{            
                    cancel();               
                  })
    

    【讨论】:

      【解决方案4】:
      import React, { Component } from "react";
      import axios from "axios";
      
      const CancelToken = axios.CancelToken;
      
      let cancel;
      
      class Abc extends Component {
        componentDidMount() {
          this.Api();
        }
      
        Api() {
            // Cancel previous request
          if (cancel !== undefined) {
            cancel();
          }
          axios.post(URL, reqBody, {
              cancelToken: new CancelToken(function executor(c) {
                cancel = c;
              }),
            })
            .then((response) => {
              //responce Body
            })
            .catch((error) => {
              if (axios.isCancel(error)) {
                console.log("post Request canceled");
              }
            });
        }
      
        render() {
          return <h2>cancel Axios Request</h2>;
        }
      }
      
      export default Abc;
      
      

      【讨论】:

      • 您应该永远在组件中使用模块范围的变量。如果你渲染了其中的两个,每个都将清除前一个设置的值。
      【解决方案5】:

      https://github.com/axios/axios#cancellation

      const CancelToken = axios.CancelToken;
                      const source = CancelToken.source();
                      let url = 'www.url.com'
      
      
                      axios.get(url, {
                          progress: false,
                          cancelToken: source.token
                      })
                          .then(resp => {
      
                              alert('done')
      
                          })
      
                      setTimeout(() => {
                          source.cancel('Operation canceled by the user.');
                      },'1000')
      

      【讨论】:

        【解决方案6】:

        通常,您希望取消先前的 ajax 请求并忽略它即将到来的响应,仅当启动该实例的新 ajax 请求时,为此,请执行以下操作:

        示例:从 API 获取一些 cmets:

        // declare an ajax request's cancelToken (globally)
        let ajaxRequest = null; 
        
        function getComments() {
        
            // cancel  previous ajax if exists
            if (ajaxRequest ) {
                ajaxRequest.cancel(); 
            }
        
            // creates a new token for upcomming ajax (overwrite the previous one)
            ajaxRequest = axios.CancelToken.source();  
        
            return axios.get('/api/get-comments', { cancelToken: ajaxRequest.token }).then((response) => {
                console.log(response.data)
            }).catch(function(err) {
                if (axios.isCancel(err)) {
                   console.log('Previous request canceled, new request is send', err.message);
                } else {
                       // handle error
                }
            });
        }
        

        【讨论】:

        【解决方案7】:

        使用 useEffect 钩子:

        useEffect(() => {
          const ourRequest = Axios.CancelToken.source() // <-- 1st step
        
          const fetchPost = async () => {
            try {
              const response = await Axios.get(`endpointURL`, {
                cancelToken: ourRequest.token, // <-- 2nd step
              })
              console.log(response.data)
              setPost(response.data)
              setIsLoading(false)
            } catch (err) {
              console.log('There was a problem or request was cancelled.')
            }
          }
          fetchPost()
        
          return () => {
            ourRequest.cancel() // <-- 3rd step
          }
        }, [])
        

        注意:对于 POST 请求,将 cancelToken 作为第三个参数传递

        Axios.post(`endpointURL`, {data}, {
         cancelToken: ourRequest.token, // 2nd step
        })
        

        【讨论】:

        • 如何触发cancelToken?假设我有点击按钮来发送请求,我怎样才能从前端停止它?
        • @NushrataraPriya 只需调用取消方法ourRequest.cancel()
        • 只会取消axios请求,不会取消节点执行。
        【解决方案8】:

        使用 cp-axios 包装器,您可以通过三种不同类型的取消 API 中止您的请求:

        1. Promise 调用 API (CPromise):

        Live browser example

         const cpAxios= require('cp-axios');
         const url= 'https://run.mocky.io/v3/753aa609-65ae-4109-8f83-9cfe365290f0?mocky-delay=5s';
         
         const chain = cpAxios(url)
              .timeout(5000)
              .then(response=> {
                  console.log(`Done: ${JSON.stringify(response.data)}`)
              }, err => {
                  console.warn(`Request failed: ${err}`)
              });
         
         setTimeout(() => {
            chain.cancel();
         }, 500);
        

        2。使用 AbortController 信号 API:

         const cpAxios= require('cp-axios');
         const CPromise= require('c-promise2');
         const url= 'https://run.mocky.io/v3/753aa609-65ae-4109-8f83-9cfe365290f0?mocky-delay=5s';
         
         const abortController = new CPromise.AbortController();
         const {signal} = abortController;
         
         const chain = cpAxios(url, {signal})
              .timeout(5000)
              .then(response=> {
                  console.log(`Done: ${JSON.stringify(response.data)}`)
              }, err => {
                  console.warn(`Request failed: ${err}`)
              });
         
         setTimeout(() => {
            abortController.abort();
         }, 500);
        

        3.使用普通的 axios cancelToken:

         const cpAxios= require('cp-axios');
         const url= 'https://run.mocky.io/v3/753aa609-65ae-4109-8f83-9cfe365290f0?mocky-delay=5s';
        
         const source = cpAxios.CancelToken.source();
         
         cpAxios(url, {cancelToken: source.token})
              .timeout(5000)
              .then(response=> {
                  console.log(`Done: ${JSON.stringify(response.data)}`)
              }, err => {
                  console.warn(`Request failed: ${err}`)
              });
         
         setTimeout(() => {
            source.cancel();
         }, 500);
        

        4.自定义 React 钩子中的用法 (Live Demo):

        import React from "react";
        import { useAsyncEffect } from "use-async-effect2";
        import cpAxios from "cp-axios";
        
        /*
         Note: the related network request will be aborted as well
         Check out your network console
         */
        
        function TestComponent({ url, timeout }) {
          const [cancel, done, result, err] = useAsyncEffect(
            function* () {
              return (yield cpAxios(url).timeout(timeout)).data;
            },
            { states: true, deps: [url] }
          );
        
          return (
            <div>
              {done ? (err ? err.toString() : JSON.stringify(result)) : "loading..."}
              <button onClick={cancel} disabled={done}>
                Cancel async effect (abort request)
              </button>
            </div>
          );
        }
        

        更新

        Axios v0.22.0+ 原生支持AbortController

        const controller = new AbortController();
        
        axios.get('/foo/bar', {
           signal: controller.signal
        }).then(function(response) {
           //...
        });
        // cancel the request
        controller.abort()
        

        【讨论】:

        • 我不推荐这种方法,因为如果您只是取消承诺,您如何确定实际请求已停止而不在后台继续? axios 内的 axios 请求最好用它的构建方式来停止。另外,我只是认为这种方式过于复杂。
        • 不,cp-axios 是一个 axios 包装器,它返回一个可取消的 Promise,它支持取消内部任务,换句话说,取消返回的 Promise 将导致相关的网络请求中止。这不仅仅是一个无声的承诺取消。只需查看上面发布的现场演示,了解当您中止承诺时相关的网络请求实际上是如何中止的(请参阅控制台中的网络选项卡)。
        猜你喜欢
        • 1970-01-01
        • 2011-05-31
        • 2020-09-13
        • 1970-01-01
        • 2012-11-21
        • 1970-01-01
        • 2018-10-31
        • 2017-10-14
        相关资源
        最近更新 更多