Lazy loaded image
如何取消HTTP请求
Words 1044Read Time 3 min
2022-1-29
2025-7-1
type
status
date
slug
summary
tags
category
icon
password
如何取消 HTTP 请求?是在面试过程中经常遇到的一个问题,并且在日常开发中也会遇到,比如不使用防抖的情况下如何取消请求,再比如一个请求等待时间过长,用户不想等了,可以取消这个请求。
最近在使用 Angular 的过程中,用到了 switchMap 操作符,发现每次发送新的请求时,上一个请求都会被自动取消掉,为了探究原理,就有了本文章。
我们知道,浏览器能发送请求,靠两个重要的 API,一个是比较老旧的 XHR,另一个比较新的 Fetch。所以本文会分别介绍使用 XHR 和 Fetch 如何取消请求,并且会分析一下 Angular 内置的 http 模块是怎样取消请求的。

XHR 取消请求

为了测试,首先创建一个 index.html 文件,内容如下,并且我们会使用 http://httpbin.org/ 提供的开放 API 来发送和取消请求。
XHR 使用实例的 abort() 方法来取消请求。
先点击 Begin,并且在 3 秒内点击 Abort,效果如下:
notion image
可以看到,在点击 Abort 的时候,当前的 HTTP 请求的 Status 会变成 canceled 的状态。

Fetch 取消请求

Fetch 使用 AbortController 来取消请求。
同样先点击 Begin,并且在 3 秒内点击 Abort,效果如下:
notion image
可以看到,当点击 Abort 之后会调用 controller 实例的 Abort 方法,并且在 singal 上订阅的 abort event 也会被执行。与 XHR 不同的是,控制台会多打印一条 Error 信息。

Angular 中的 http 模块取消请求

了解了 XHR 和 Fetch 取消请求的方式之后,我们来看一下 Angular 中是使用的哪种方式。
首先在 sandbox 上创建一个 Angular 项目,地址:演示代码
通过多次点击按钮可以发现,每次点击都会先取消上一个请求,并且发送新的请求。那么 Angular 和 RxJS 内部是怎么实现的呢?
带着这个问题,我们首先来看 switchMap 的代码:switchMap
其中有这么几行是我们关心的:
我们知道 switchMap 操作符的行为是每次上游产生数据的时候都会去调用函数参数 project,只要有新的内部 Observable 产生,就会立刻退订之前的内部 Observable 对象,所以 Angular 中取消 http 请求的代码应该是该请求内部 Observable 的返回值,比如对应到演示代码中就是 this.http.get(url)方法内部 Observable 的返回值。
接下来我们去查看 Angular http 模块的 get 方法,地址:client.ts
通过查看代码,可以发现 get 方法会调用一个名为 handle 的函数,这个函数返回了一个 Observable,而这个 Observable 的返回值也是一个函数,代码如下:
通过 abort 和变量命名也能猜出来,Angular 中内置的 http 模块是使用的 XHR 来发送请求,更详细的过程可以阅读 Angular http 模块的源码。
 
上一篇
二叉树的前序、中序和后序遍历
下一篇
Angular使用ng-content进行内容投影