超时取消HTTP请求的方法

阅读 22

在系统监控与心跳探活等场景中,我们常常会对某些设备或API接口发起HTTP请求,如果超时就算失败,因为一直等待下去没有太大的意义。

那么,这就会涉及到一个问题:如何将发起的Ajax请求设置为超时取消呢?

XHR(老式汽车)

XHR 全称是 XMLHttpRequest,它是浏览器最早提供的、用来实现 Ajax 思想的内置函数。可以说,它是 Ajax 技术的“鼻祖”。

它自带 xhr.timeout  和 xhr.abort(),但基于回调函数的 API 极其冗长,且无法优雅地配合现代的 async/await 异步流。

随着Fetch方法的出现,XHR已经慢慢被淘汰了。

Fetch(新式高铁)

但是,在Fetch早期,我们却无法使用它来实现真正的底层网络取消。

开发者常用如下写法来模拟超时:

Promise.race([fetch(), timeoutPromise()])

但这种写法只能让代码提前抛出异常,底层的 TCP 连接和 HTTP 请求在后台依然会继续传输,无法省去带宽消耗,也无法减轻服务端压力。

为了解决这个问题,人们引入了AbortController ,用它结合setTimeout来实现要求:

const controller = new AbortController()

const timeout = setTimeout(() => {
  controller.abort()
}, 5000)

try {
  const response = await fetch(url, {
    method: 'GET',
    signal: controller.signal
  })

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}`)
  }
} finally {
  clearTimeout(timeout)
}

这种方式虽然能满足上面的要求,但是实现较繁琐(需维护 controller 与 timer )。

在纯超时场景下(无需手动提前取消请求)AbortSignal.timeout()方法可以更简洁地实现该要求:

try {
  const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
  const result = await res.json();
  // …
}

需要注意的是,后者推出的时间更晚,需要考虑当前环境的兼容性问题。

另外,前者抛出的异常是AbortErrorAbortSignal.timeout()抛出的是TimeoutError

参考

最后编辑于: 2026-08-26

评论(0条)

(必填)
复制成功