如何取消HTTP fetch()请求?

Sam*_*Lee 168 javascript ajax fetch-api

有一个用于从JavaScript发出请求的新API:fetch().是否有任何内置机制可以在飞行中取消这些请求?

Sud*_*Plz 221

TL/DR:

fetch现在支持signal截至2017年9月20日的参数,但并非所有浏览器都支持此atm.

这是我们很快就会看到的变化,因此您应该可以使用AbortControllers 取消请求AbortSignal.

长版

如何:

它的工作方式是这样的:

第1步:你创建一个AbortController(现在我只是用过这个)

const controller = new AbortController()

第2步:你得到这样AbortController的信号:

const signal = controller.signal

第3步:你signal像这样传递给fetch:

fetch(urlToFetch, {
    method: 'get',
    signal: signal, // <------ This is our AbortSignal
})
Run Code Online (Sandbox Code Playgroud)

第4步:在需要时立即中止:

controller.abort();

以下是它如何工作的示例(适用于Firefox 57+):

<script>
    // Create an instance.
    const controller = new AbortController()
    const signal = controller.signal

    /*
    // Register a listenr.
    signal.addEventListener("abort", () => {
        console.log("aborted!")
    })
    */


    function beginFetching() {
        console.log('Now fetching');
        var urlToFetch = "https://httpbin.org/delay/3";

        fetch(urlToFetch, {
                method: 'get',
                signal: signal,
            })
            .then(function(response) {
                console.log(`Fetch complete. (Not aborted)`);
            }).catch(function(err) {
                console.error(` Err: ${err}`);
            });
    }


    function abortFetching() {
        console.log('Now aborting');
        // Abort.
        controller.abort()
    }

</script>



<h1>Example of fetch abort</h1>
<hr>
<button onclick="beginFetching();">
    Begin
</button>
<button onclick="abortFetching();">
    Abort
</button>
Run Code Online (Sandbox Code Playgroud)

资料来源:

  • 但现在它不适用于其他浏览器,即Chrome,因为"AbortController未定义".无论如何,这只是一个概念证明,至少Firefox 57+的人可以看到它的工作原理 (3认同)
  • 这是纯粹的StackOverflow黄金,感谢简洁的写作!而bugtracker链接也是如此! (3认同)
  • 现在所有现代浏览器都支持它.https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort查看底部的表格 (3认同)
  • 谢谢,但我还有一个问题,我们是否应该手动将信号改回 true 以便下次获取? (3认同)
  • 这个答案是正确的,应予以赞成.但我冒昧地对代码片段进行了一些编辑,因为它实际上并没有在Firefox 57+中工作 - 垫片似乎导致它失败(*"Err:TypeError:'signal'成员RequestInit没有实现接口AbortSignal."*)并且https://slowwly.robertomurray.co.uk/的证书似乎存在一些问题(*"这个服务器无法证明它是slowwly.robertomurray.co.英国;它的安全证书来自*.herokuapp.com."*),所以我改为使用http://slowwly.robertomurray.co.uk/(普通的http). (2认同)
  • @akshaykishore 一旦使用了 AbortController 的实例,我们需要创建一个新实例来重置该值。https://dev.to/beejluig/cancel-fetch-with-abortcontroller-2435 (2认同)

spr*_*pro 58

我不相信有一种方法可以使用现有的fetch API取消请求.有关它的讨论正在https://github.com/whatwg/fetch/issues/27上进行

2017年5月更新:仍无法解决.请求无法取消.更多讨论,访问https://github.com/whatwg/fetch/issues/447

  • #27现在关闭.讨论在https://github.com/whatwg/fetch/issues/447. (5认同)

Jay*_*yen 15

https://developers.google.com/web/updates/2017/09/abortable-fetch

建立:

// setup AbortController
const controller = new AbortController();
// signal to pass to fetch
const signal = controller.signal;

// fetch as usual
fetch(url, { signal }).then(response => {
  ...
}).catch(e => {
  // catch the abort if you like
  if (e.name === 'AbortError') {
    ...
  }
});

// when you want to abort
controller.abort();
Run Code Online (Sandbox Code Playgroud)

中止: __CODE__

在边缘16(2017-10-17),firefox 57(2017-11-14),桌面游猎11.1(2018-03-29),ios safari 11.4(2018-03-29),chrome 67(2018-05)工作-29),以及之后.


Ant*_*ris 6

自2018年2月起,fetch()可以使用 Chrome下面的代码取消(阅读使用可读流以启用Firefox支持).没有错误catch()提起,这是一个临时的解决方案,直到AbortController完全采用.

fetch('YOUR_CUSTOM_URL')
.then(response => {
  if (!response.body) {
    console.warn("ReadableStream is not yet supported in this browser.  See https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream")
    return response;
  }

  // get reference to ReadableStream so we can cancel/abort this fetch request.
  const responseReader = response.body.getReader();
  startAbortSimulation(responseReader);

  // Return a new Response object that implements a custom reader.
  return new Response(new ReadableStream(new ReadableStreamConfig(responseReader)));
})
.then(response => response.blob())
.then(data => console.log('Download ended. Bytes downloaded:', data.size))
.catch(error => console.error('Error during fetch()', error))


// Here's an example of how to abort request once fetch() starts
function startAbortSimulation(responseReader) {
  // abort fetch() after 50ms
  setTimeout(function() {
    console.log('aborting fetch()...');
    responseReader.cancel()
    .then(function() {
      console.log('fetch() aborted');
    })
  },50)
}


// ReadableStream constructor requires custom implementation of start() method
function ReadableStreamConfig(reader) {
  return {
    start(controller) {
      read();
      function read() {
        reader.read().then(({done,value}) => {
          if (done) {
            controller.close();
            return;
          }
          controller.enqueue(value);
          read();
        })
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 这不是 OP 所要求的。他们想要取消读取而不是读取器。Fetch 的承诺直到请求完成后才会解析,这对于取消对服务器的请求为时已晚。 (2认同)

Bra*_*rad 5

正如@spro所说,目前还没有合适的解决方案。

但是,如果您有正在进行的响应并且正在使用 ReadableStream,则可以关闭流以取消请求。

fetch('http://example.com').then((res) => {
  const reader = res.body.getReader();

  /*
   * Your code for reading streams goes here
   */

  // To abort/cancel HTTP request...
  reader.cancel();
});
Run Code Online (Sandbox Code Playgroud)