我有一个fetch-api POST请求:

fetch(url, {
  method: 'POST',
  body: formData,
  credentials: 'include'
})

我想知道这个的默认超时时间是多少?我们如何将它设置为特定的值,比如3秒或不定秒?


当前回答

下面是一个使用NodeJS的SSCCE,它将在1000ms后超时:

import fetch from 'node-fetch';

const controller = new AbortController();
const timeout = setTimeout(() => {
    controller.abort();
}, 1000); // will time out after 1000ms

fetch('https://www.yourexample.com', {
    signal: controller.signal,
    method: 'POST',
    body: formData,
    credentials: 'include'
}
)
.then(response => response.json())
.then(json => console.log(json))
.catch(err => {
    if(err.name === 'AbortError') {
        console.log('Timed out');
    }}
)
.finally( () => {
    clearTimeout(timeout);
});

其他回答

  fetchTimeout (url,options,timeout=3000) {
    return new Promise( (resolve, reject) => {
      fetch(url, options)
      .then(resolve,reject)
      setTimeout(reject,timeout);
    })
  }

更新,因为我最初的答案有点过时,我建议使用像这里实现的中止控制器:https://stackoverflow.com/a/57888548/1059828或看看这个非常好的帖子解释中止控制器与fetch:我如何取消HTTP fetch()请求?

过时的原答案:

我非常喜欢使用Promise.race这种简洁的方法

fetchWithTimeout.js

export default function (url, options, timeout = 7000) {
    return Promise.race([
        fetch(url, options),
        new Promise((_, reject) =>
            setTimeout(() => reject(new Error('timeout')), timeout)
        )
    ]);
}

main.js

import fetch from './fetchWithTimeout'

// call as usual or with timeout as 3rd argument

// throw after max 5 seconds timeout error
fetch('http://google.com', options, 5000) 
.then((result) => {
    // handle result
})
.catch((e) => {
    // handle errors and timeout error
})

正确的错误处理技巧


正常的做法:

为了在大多数情况下增加超时支持,建议引入一个Promise实用函数,如下所示:

function fetchWithTimeout(resource, { signal, timeout, ...options } = {}) {
  const controller = new AbortController();
  if (signal != null) signal.addEventListener("abort", controller.abort);
  const id = timeout != null ? setTimeout(controller.abort, timeout) : undefined;
  return fetch(resource, {
    ...options,
    signal: controller.signal
  }).finally(() => {
    if (id != null) clearTimeout(id);
  });
}

调用控制器。abort或拒绝setTimeout回调函数中的承诺会扭曲堆栈跟踪。

这是次优的,因为如果需要对错误后日志进行分析,就必须在调用fetch方法的函数中添加带有日志消息的样板错误处理程序。


好专业知识:

为了保留错误及其堆栈跟踪,可以应用以下技术:

function sleep(ms = 0, signal) { return new Promise((resolve, reject) => { const id = setTimeout(() => resolve(), ms); signal?.addEventListener("abort", () => { clearTimeout(id); reject(); }); }); } async function fetch( resource, options ) { const { timeout, signal, ...ropts } = options ?? {}; const controller = new AbortController(); let sleepController; try { signal?.addEventListener("abort", () => controller.abort()); const request = nodeFetch(resource, { ...ropts, signal: controller.signal, }); if (timeout != null) { sleepController = new AbortController(); const aborter = sleep(timeout, sleepController.signal); const race = await Promise.race([aborter, request]); if (race == null) controller.abort(); } return request; } finally { sleepController?.abort(); } } (async () => { try { await fetchWithTimeout(new URL(window.location.href), { timeout: 5 }); } catch (error) { console.error("Error in test", error); } })();

在取回API中还没有超时支持。但这可以通过一个承诺来实现。

如。

  function fetchWrapper(url, options, timeout) {
    return new Promise((resolve, reject) => {
      fetch(url, options).then(resolve, reject);

      if (timeout) {
        const e = new Error("Connection timed out");
        setTimeout(reject, timeout, e);
      }
    });
  }

一个更简单的方法是在MDN中:https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal#aborting_a_fetch_operation_with_a_timeout

try {
    await fetch(url, { signal: AbortSignal.timeout(5000) });
} catch (e) {
    if (e.name === "TimeoutError") {
        console.log('5000 ms timeout');
    }
}