如何中断已发出去的请求?

news/2024/7/19 14:53:01 标签: web, ajax, js, java, javascript
js_content">

↓推荐关注↓

面试官:请求已经发出去了,如何取消掉这个已经发出去的请求?

面试者:(脑海里立马产生一个疑惑:已经发出去的请求还能取消掉?) 这个......这个......还真不知道。

面试完,马上找度娘.....

AbortController

AbortController[1] 接口表示一个控制器对象,可以根据需要终止一个或多个Web请求。

  • AbortController():AbortController()构造函数创建一个新的 AbortController 对象实例

  • signal:signal 属性返回一个 AbortSignal 对象实例,它可以用来 with/about 一个Web(网络)请求

  • abort():终止一个尚未完成的Web(网络)请求,它能够终止 fetch 请求,任何响应Body的消费者和流

Fetch 中断请求

Fetch 是 Web 提供的一个用于获取资源的接口,如果要终止 fetch 请求,则可以使用 Web 提供的 AbortController 接口。

首先我们使用 AbortController() 构造函数创建一个控制器,然后使用 AbortController.signal 属性获取其关联 AbortSignal 对象的引用。

当一个 fetch request 初始化时,我们把 AbortSignal 作为一个选项传递到请求对象 (如下:{signal}) 。这将信号和控制器与获取请求相关联,然后允许我们通过调用 AbortController.abort() 中止请求。

const controller = new AbortController();
let signal = controller.signal;
 console.log( signal 的初始状态:  , signal);

const downloadBtn = document.querySelector( .download );
const abortBtn = document.querySelector( .abort );

downloadBtn.addEventListener( click , fetchVideo);

abortBtn.addEventListener( click , function() {
  controller.abort();
 console.log( signal 的中止状态:  , signal);
});

function fetchVideo() {
  //...
  fetch(url, {signal}).then(function(response) {
    //...
  }).catch(function(e) {
    reports.textContent =  Download error:   + e.message;
  })
}

当我们中止请求后,网络请求变成了如下所示的情况:

c3d3ddc70322877e03beb42c2f33dd40.png

我们再来看看 AbortSignal 中止前和中止后的状态:

5a53e8d0f7f25d29a70b3ffc3ed30d52.png

可以看到,AbortSignal 对象的 aborted 属性由初始时的 false 变成了中止后的 true 。

线上运行示例[2] (代码来源于MDN[3])

AbortControllter 有兼容性问题,如下:

e711715e9c73ddc9ce076b40f48f6626.png

axios 中断请求

axions 中断请求有两种方式:

方式一

使用 CancelToken.souce 工厂方法创建一个 cancel token,代码如下:

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get( https://mdn.github.io/dom-examples/abort-api/sintel.mp4 , {
  cancelToken: source.token
}).catch(function (thrown) {
  // 判断请求是否已中止
  if (axios.isCancel(thrown)) {
    // 参数 thrown 是自定义的信息
    console.log( Request canceled , thrown.message);
  } else {
    // 处理错误
  }
});

// 取消请求(message 参数是可选的)
source.cancel( Operation canceled by the user. );

中止后的网络请求变成如下所示:

10f364d2ff959d15f0b6944bb6b5a11d.png

我们再来看看初始时和中止后的 souce 状态:

c530356c7e29e7188f3ef69662c49d0f.png

可以看到,初始时和中止后的 source 状态并没还有发生改变。那么我们是如何判断请求的中止状态呢?axios 为我们提供了一个 isCancel() 方法,用于判断请求的中止状态。isCancel() 方法的参数,就是我们在中止请求时自定义的信息。

e95520ebd4e742ec92ab46f39eb66566.png

方式二

通过传递一个 executor 函数到 CancelToken 的构造函数来创建一个 cancel token:

const CancelToken = axios.CancelToken;
let cancel;

axios.get( /user/12345 , {
  cancelToken: new CancelToken(function executor(c) {
    // executor 函数接收一个 cancel 函数作为参数
    cancel = c;
  })
});

// 取消请求
cancel( Operation canceled by the user. );

浏览器运行结果与方式一一致,此处不再赘述。

线上运行示例[4] (代码来源于MDN[3])

umi-request 中断请求

umi-request 基于 fetch 封装, 兼具 fetch 与 axios 的特点, 中止请求与 fetch 和 axios 一致不再过多赘述,详情可见官方文档 中止请求[5]

需要注意的是 AbortController 在低版本浏览器polyfill有问题,umi-request 在某些版本中并未提供 AbortController 的方式中止请求。

umi 项目中使用 CancelToken 中止请求

umi 项目中默认的请求库是umi-request,因此我们可以使用umi-request提供的方法来中止请求。另外,在umi项目中可以搭配使用了dva,因此下面简单介绍下在dva中使用CancelToken中止请求的流程。

1、在 services 目录下的文件中编写请求函数和取消请求的函数

import request from  @/utils/request ;
const CancelToken = request.CancelToken;
let cancel: any;

// 合同文件上传 OSS
export async function uploadContractFileToOSS(postBody: Blob): Promise<any> {
  return request(`/fms/ossUpload/financial_sys/contractFile`, {
    method: "POST",
    data: postBody,
    requestType:  form ,
    // 传递一个 executor 函数到 CancelToken 的构造函数来创建一个 cancel token
    cancelToken: new CancelToken((c) => {
      cancel = c
    })
  })
}

// 取消合同文件上传
export async function cancelUploadFile() {
  return cancel && cancel()
}

2、在 models 中编写 Effect:

*uploadContractFileToOSS({ payload }: AnyAction, { call, put }: EffectsCommandMap): any {
  const response = yield call(uploadContractFileToOSS, payload);
  yield put({
    type:  save ,
    payload: {
      uploadOSSResult: response?.data,
    }
  })
  return response?.data
},

*cancelUploadFile(_: AnyAction, { call }: EffectsCommandMap): any {
  const response = yield call(cancelUploadFile)
  return response

},

3、在页面中通过dispatch函数触发相应的action:

// 发起请求
dispatch({
  type:  contract/fetchContractFiles ,
  payload: {
    contractId: `${id}`,
  }
})

// 取消请求
dispatch({
  type: "contract/cancelUploadFile"
})

4、在 utils/request.js 中统一处理中止请求的拦截:

const errorHandler = (error: { response: Response }): Response => {
  const { response } = error;
  notification.destroy()

  if (response && response.status) {
    const errorText = codeMessage[response.status] || response.statusText;
    const { status, url } = response;

    notification.error({
      message: `请求错误 ${status}: ${url}`,
      description: errorText,
    });
  } else if (error?.[ type ] ===  TypeError ) {
    notification.error({
      description:  您的网络发生异常,无法连接服务器 ,
      message:  网络异常 ,
    });
  } else if (error?.[ request ]?.[ options ]?.[ cancelToken ]) {
    notification.warn({
      description:  当前请求已被取消 ,
      message:  取消请求 ,
    });
  } else if (!response) {
    notification.error({
      description:  您的网络发生异常,无法连接服务器 ,
      message:  网络异常 ,
    });
  } else {
    notification.error({
      description:  请联系网站开发人员处理 ,
      message:  未知错误 ,
    });
  }
  return response;
};

参考资料

[1]

AbortController: https://developer.mozilla.org/zh-CN/docs/Web/API/AbortController

[2]

线上运行示例: https://codesandbox.io/s/abortcontroller-cancel-request-f4wzo

[3]

MDN: https://github.com/mdn/dom-examples/blob/master/abort-api/

[4]

线上运行示例: https://codesandbox.io/s/axios-cancel-request-qp0q7?file=/index.html

[5]

中止请求: https://github.com/umijs/umi-request/blob/master/README_zh-CN.md#%E9%80%9A%E8%BF%87-abortcontroller-%E6%9D%A5%E4%B8%AD%E6%AD%A2%E8%AF%B7%E6%B1%82

作者:紫圣

https://juejin.cn/post/7033906910583586829

- EOF -

点赞和在看就是最大的支持❤️


http://www.niftyadmin.cn/n/1250911.html

相关文章

啥?css 也有状态管理

CSS用于交互的方式无非就那么几种&#xff1a;伪类&#xff1a;:hover、:link、:active ...动画&#xff1a;animation过渡动画&#xff1a;transition这些交互方式组合起来&#xff0c;真的可以玩出一些花样&#xff0c;例如我们本文的主题&#xff0c;CSS的状态管理&#xff…

vue3 区别于 vue2 的“与众不同”

希望本篇文章能帮你加深对 Vue 的理解&#xff0c;能信誓旦旦地说自己熟练Vue2/3。除此之外&#xff0c;也希望路过的朋友可以帮助我查漏补缺&#x1f91e;。内容混杂用法 原理 使用小心得&#xff0c;建议收藏&#xff0c;慢慢看。区别生命周期的变化整体来看&#xff0c;变…

搞事情,这种跨域方案快要被禁用了!

一句话描述document.domain 将变为可读属性。别着急&#xff0c;预计最早变化时间是 Chrome 101 版本&#xff0c;现在最新版是 97。对我们有啥影响&#xff1f;如果你的业务里有通过更改 document.domain 来进行跨域的场景&#xff0c;马上就芭比Q了&#xff0c;得快点进行改造…

2022 前端领域的新变化

vue3步入成年期想必大家看到了 "Vue 3 将在 2022 年 2 月 7 日成为新的默认版本&#xff01;" 的新闻了&#xff0c;目前各个大厂都有团队开始在新的项目上使用 Vue 3 &#xff0c;许多活跃的小公司也纷纷加入行列&#xff0c;这预示着 Vue 3 已经开始步入了成年期&a…

前端工程师生产环境 debugger 小技巧

本文首发于政采云前端团队博客&#xff1a;前端工程师生产环境 debugger 技巧https://www.zoo.team/article/prod-debugger导言开发环境 debug 是每个程序员上岗的必备技能。生产环境呢&#xff1f;虽然生产环境 debug 是一件非常不优雅的行为&#xff0c;但是由于种种原因&…

postman遇到对手了?这个神器从接口设计、调试到管理一站式全包

作为软件开发从业者&#xff0c;API 调试是必不可少的一项技能&#xff0c;在这方面 Postman 做的非常出色。但是在整个软件开发过程中&#xff0c;API 调试只是其中的一部分&#xff0c;还有很多事情 Postman 无法完成&#xff0c;或者无法高效完成&#xff0c;比如&#xff1…

专业前端 console 大法

‍作者&#xff1a;正经程序员链接&#xff1a;https://juejin.cn/post/7065856171436933156学习前端开发时&#xff0c;几乎最先学习的就是console.log()。毕竟多数人的第一行代码都是&#xff1a;console.log( Hello World );console对象提供了对于浏览器调试控制台的访问&am…

通过几行 JS 就可以读取电脑上的所有数据?

Spectre如果一个漏洞很难构造&#xff0c;就算他能够造成再大的危害&#xff0c;可能也不会引起浏览器这么大的重视&#xff0c;那么我们今天的主角 Spectre &#xff0c;是又容易构造&#xff0c;而且造成的危害也很大的&#xff0c;利用 Spectre &#xff0c;你可以&#xf…