108

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

    $(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

4

10 回答 10

146

Axios 目前不支持取消请求。请参阅此问题了解详细信息。

更新:在 axios v0.15 中添加了取消支持。

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

例子:

const cancelTokenSource = axios.CancelToken.source();

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

// Cancel request
cancelTokenSource.cancel();
于 2016-07-13T13:37:31.713 回答
37

使用 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
})
于 2020-05-04T08:55:19.207 回答
26
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;

于 2019-03-06T11:52:52.803 回答
24

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

示例:从 API 获取一些评论:

// 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
        }
    });
}
于 2019-12-12T07:01:54.120 回答
6

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

于 2017-05-17T16:37:17.933 回答
6

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')
于 2019-11-25T12:12:02.157 回答
5

这就是我在 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();               
              })
于 2017-07-25T07:24:15.393 回答
4

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

1. Promise 调用 API(CPromise):

实时浏览器示例

 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 钩子中的用法现场演示):

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()
于 2020-09-27T12:19:33.030 回答
0

从 v0.22.0 开始,Axios 支持 AbortController 以 fetch API 方式取消请求:

const controller = new AbortController();

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

CancelToken deprecated 您还可以使用 CancelToken 取消请求。

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

此 API 自 v0.22.0 起已弃用,不应在新项目中使用

您可以使用 CancelToken.source 工厂创建取消令牌,如下所示:

于 2022-03-04T08:51:22.850 回答
0
import {useState, useEffect} from 'react'

export function useProfileInformation({accessToken}) {
  const [profileInfo, setProfileInfo] = useState(null)

  useEffect(() => {
    const abortController = new AbortController()

    window
      .fetch('https://api.example.com/v1/me', {
        headers: {Authorization: `Bearer ${accessToken}`},
        method: 'GET',
        mode: 'cors',
        signal: abortController.signal,
      })
      .then(res => res.json())
      .then(res => setProfileInfo(res.profileInfo))

    return function cancel() {
      abortController.abort()
    }
  }, [accessToken])

  return profileInfo
}

// src/app.jsx
import React from 'react'
import {useProfileInformation} from './hooks/useProfileInformation'

export function App({accessToken}) {
  try {
    const profileInfo = useProfileInformation({accessToken})

    if (profileInfo) {
      return <h1>Hey, ${profileInfo.name}!</h1>
    } else {
      return <h1>Loading Profile Information</h1>
    }
  } catch (err) {
    return <h1>Failed to load profile. Error: {err.message}</h1>
  }
}
于 2022-03-04T11:56:32.087 回答