前端axios取消请求总结详解

目录
  • 应用场景
  • 如何取消请求
  • 项目中用法示例
  • 批量取消请求
  • 切换路由时,取消请求
  • 取消请求的实现原理

应用场景

取消请求在前端有时候会用到,以下是两个工作中可能会用到的场景

  • tab切换时刷新某个列表数据,如果他们共用一个变量存储数据列表,当请求有延时,可能会导致两个tab数据错乱;
  • 导出文件或下载文件时,中途取消 。

如何取消请求

取消http请求,axios文档里提供了两种用法:

第一种:使用 CancelToken

const { CancelToken, isCanCel } = axios;
const source = CancelToken.source();
axios.get('/user/12345', {
  cancelToken: source.token
}).catch(thrown => {
  if (isCancel(thrown)) {
    // 获取 取消请求 的相关信息
    console.log('Request canceled', thrown.message);
  } else {
    // 处理其他异常
  }
});
axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})
// 取消请求。参数是可选的,参数传递一个取消请求的相关信息,在 catch 钩子函数里能获取到
source.cancel('Operation canceled by the user.');

第二种:给构造函数 CancelToken 传递一个 executor 函数作为参数。这种方法的好处是,可以用同一个 cancel token 来取消多个请求

const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // 参数 c 也是个函数
    cancel = c;
  })
});
// 取消请求,参数用法同上
cancel();

项目中用法示例

在一个真实的项目中,一般都会对axios进行二次封装,针对请求、响应、状态码、code等做处理。贴一个项目里常用的request.js:

import axios from 'axios'
import store from '@/store'
import { getToken } from '@/utils/auth'
// 创建一个 axios 实例,并改变默认配置
const service = axios.create({
  baseURL: process.env.BASE_API, // api 的 base_url
  timeout: 5000 // request timeout
})
// 请求拦截
service.interceptors.request.use(
  config => {
    // Do something before request is sent
    if (store.getters.token) {
      // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
      config.headers['X-Token'] = getToken()
    }
    return config
  },
  error => {
    // Do something with request error
    console.log(error) // for debug
    Promise.reject(error)
  }
)
// 响应拦截
service.interceptors.response.use(
  response => response,
  error => {
    alert(error)
    return Promise.reject(error)
  }
)
export default service

对于某一个请求添加取消的功能,要在调用api时,加上cancelToken选项,使用时的示例:

// api.js
import request from 'request'
export function getUsers(page, options) {
  return request({
    url: 'api/users',
    params: {
      page
    },
    ...options
  })
}
// User.vue
import { CancelToken, isCancel } from 'axios'
import { getUsers } from 'api'
...
cancel: null
...
toCancel() {
  this.cancel('取消请求')
}
getUsers(1,
  {
    cancelToken:  new CancelToken(c => (this.cancel = c))
  }
)
.then(...)
.catch(err => {
  if (isCancel) {
    console.log(err.message)
  } else {
    ...
  }
})

以上,我们就可以顺顺利利地使用封装过的axios,取消某一个请求了。其原理无非就是把cancelToken的配置项,在调用api时加上,然后就可以在业务代码取消特定请求了。

批量取消请求

在 document 里的第二种方法已经说过:通过指定同一个cancel token来取消。但是,在上面的项目示例中,不能控制拿到相同的cancel token。我们可以换个思路:用数组保存每个需要取消的cancel token,然后逐一调用数组里的每一项即可:

// User.vue
import { CancelToken, isCancel } from 'axios'
import { getUsers } from 'api'
...
cancel: []
...
toCancel() {
  while (this.cancel.length > 0) {
    this.cancel.pop()('取消请求')
  }
}
getUser1(1,
  {
    cancelToken:  new CancelToken(c1 => (this.cancel.push(c1)))
  }
)
getUser2(2,
 {
  cancelTokem: new CancleTokem(c2 => (this.cancel.push(c2)))
 }
)

切换路由时,取消请求

上面讲了取消一个请求及页面内批量abort的方法,此外,还有一种需求——切换路由时,取消所有。 这里不详细赘述了,大概思路就是在请求拦截器里,统一加个token,并设置全局变量source控制一个cancel token,在路由变化时调用cancel方法。

http.interceptors.request.use(config => {
    config.cancelToken = store.source.token
    return config
}, err => {
    return Promise.reject(err)
})
router.beforeEach((to, from, next) => {
    const CancelToken = axios.CancelToken
    store.source.cancel && store.source.cancel()
    store.source = CancelToken.source()
    next()
})
// 全局变量
store = {
    source: {
        token: null,
        cancel: null
  }
}

取消请求的实现原理

cancelToken的source方法维护了一个对象,里面包括了token令牌和cancel方法,token来自与构造函数CancelToken,调用cancel方法后,token的promise状态为resolved,进而又调用了xhr的abort方法,取消请求成功。 来分析下取消请求是怎么实现的,先从一个简单的取消请求的例子开始:

var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios.get('/get?name=xmz', {
    cancelToken : source.token
}).then((response)=>{
    console.log('response', response)
}).catch((error)=>{
    if(axios.isCancel(error)){
        console.log('取消请求传递的消息', error.message)
    }else{
        console.log('error', error)
    }
})
// 取消请求
source.cancel('取消请求传递这条消息');

这就是一个简单的取消请求的例子,那么就从最开始的axios.CancelToken来看,先去axios/lib/axios.js文件中。

axios.CancelToken = require('./cancel/CancelToken');

不费吹灰之力,就找到了CancelToken,在例子中我们调用了source方法,那么就去axios/lib/cancel/CancelToken.js文件中看看这个source方法到底是干什么的?

CancelToken.source = function(){
    var cancel;
    var token = new CancelToken(function executor(c) {
        cancel = c
    })
    return {
        token : token,
        cancel : cancel
    }
}

source方法很简单,就是返回一个具有token和cancel属性的对象,但是token和cancel都是通过CancelToken这个构造函数来的,那么还在这个文件中向上看,找到CancelToken函数。

function CancelToken (executor){
    // ...
    // 判断executor是一个函数,不然就报错
    var resolvePromise;
    this.promise = new Promise(function(resolve){
        resolvePromise = resolve;
    })
    var token = this;
    // 以上token现在有一个promise属性,是一个未成功的promise对象;
    executor(function cancel(message){
        if(token.reason){
            return;
        }
        token.reason = new Cancel(message);
        resolvePromise(token.reason);
    })
    // 这个cancel函数就是 上面函数中的cancel,也就是source.cancel;
}

现在知道了source.cancel是一个函数,souce.token是一个实例化对象,暂时就知道这些,继续看文章最开始的例子,接下来是去发送请求了,最下面还有一行代码是执行souce.cancel(); souce.cancel就是用来触发取消请求的函数。 现在再回头来看,上面的cancel函数,cancel执行,给token加了一个reason属性,那么看下这个reason属性是什么吧,看下这个Cancel构造函数,在axios/lib/cancel/Cancel.js文件中

function Cancel(message){
    this.message = message
}

Cancel特别简单就是给实例化对象添加一个message属性,所以现在token.reason是一个具有message属性的对象了。 继续回到cancel函数中,resolvePromise函数执行了,那么token.promise对象,这个原本未变成,成功状态的promise,变成了成功状态了,并且将token.reason对象传递过去了。 简单总结一下,执行取消函数,就是让token的promise的状态变成了成功; 好了,突然发现分析中断了,变成成功状态又怎样了,怎么取消的呢?虽然现在的同步代码都执行完了,但是请求还没发送出去呢,我们还要去看发送请求的函数

在分析发送请求之前,再看下最开始的例子,和最普通的发送一个get请求还是有一点区别的,配置对象中多了,一个cancelToken的属性,值是token,到底起了什么作用呢,去axios/lib/adapters/xhr.js中一探究竟(这里只截取其中关于cancelToken的部分)。

// 在发送请求之前,验证了cancelToken,看来此处就是用来取消请求的;
if(config.cancelToken){
    // 具体是如何取消的,是在这个判断内定义的;
    config.cancelToken.promise.then(function(cancel){
        request.abort();
        reject(cancel);
        request = null;
    })
}
// 发送请求
request.send(requestData);

仔细看这只是一个promise的then函数,只有在promise的状态变成成功后才会执行,而刚才我们分析了,cancel就是让这个promise的状态变成成功,所以如果执行了,取消请求的函数,这个then就会执行,取消发送请求,并且把发送请求的promise变成reject,被axiox.get().catch()捕获; 流程已经清楚了,最后再总结一下: 执行cancel是让token的promise变成成功,在真正发送请求之前,验证token.promise的状态是否已经变了,如果变了,就取消请求,就是这样一个简单的思想来进行取消请求的。

以上就是axios取消请求总结的详细内容,更多关于axios取消请求的资料请关注我们其它相关文章!

(0)

相关推荐

  • Typescript 封装 Axios拦截器方法实例

    目录 引言 创建 class axios.create([config]) 封装 request(config)通用方法 封装-拦截器(单个实例独享) 扩展 Http 自定义拦截器 封装-拦截器(所有实例共享) 封装-拦截器(单个请求独享) 装修 Http class 返回经过 request 返回数据结构(DTO) 拦截器执行顺序 操作场景控制 引言 对 axios 二次封装,更加的可配置化.扩展性更加强大灵活 通过 class 类实现,class 具备更强封装性(封装.继承.多态),通过实例

  • axios库的核心代码解析及总结

    目录 一.关键步骤 1.创建axios对象 2.请求 二.Axios类 1.基础属性 2.辅助方法 3.request方法 三.adpter适配器 1.xhradpter 2.httpadpter 一.关键步骤 1.创建axios对象 axios库导出的对象是一个已经被创建好的axios对象,它本质上是一个方法,可以直接接收一个config配置参数进行请求.在库的入口处,即可看到如下代码: function createInstance(defaultConfig) { // 传入默认配置生成a

  • axios接口管理优化操作详解

    目录 强化功能 接口文件写法简化 任务调度.Loading调度 提示信息自由化 总结 强化功能 本文针对中大型的后台项目的接口模块优化,在不影响项目正常运行的前提下,增量更新. 接口文件写法简化(接口模块半自动化生成) 任务调度.Loading调度(接口层面的防抖兜底,多个接口共用一个loading,防止闪烁) 接口提示自由化(提示消息可由前端控制,也可以由后端控制) 接口文件写法简化 对于一些中后台模块的接口,基本上都是增删改查以及审核流的一些功能(其他特殊接口暂且不谈).如果后端接口足够规范

  • 从axios源码角度解决bug的过程记录

    目录 现象 排查思路 1. 引入 vConsole 在移动端调试 2. 从大范围到小范围的 log 3. axios 源码一览 排查角度 - interceptor 排查角度 - xhr 4. 解决问题 现象 公司的一个 H5 站点在头条 App 里白屏,在手百.QQ 浏览器.Safari.Chrome 等都正常 排查思路 1. 引入 vConsole 在移动端调试 因为移动端没有 PC 里那样方便的调试工具可以清晰的查看 log 和 network 之类有用的信息,只能借助 vConsole.

  • vue3 axios 实现自动化api配置详解

    目录 概述 示例 约定 请求 URL 的约定 请求传参的约定 分页列表,请求参数约定 分页列表 响应示例 响应码 code 的约定 请求跨域问题解决方案 全局配置 配置说明coder/config.js 模型配置 1.实现对一个实体进行增.删.改.查.导出.唯一性校验 2.只需要增.删.改.查中得某些操作,可以指定生成你需要的方法 3.自定义方法配置 4.指定请求接口地址前缀 概述 在实践中,我们发现上述的代码重复率非常高,新增和修改都费力,并且是没技术含量的体力活. 但又必须要这样做,不适合以

  • 封装 axios+promise通用请求函数操作

    我就废话不多说了,大家还是直接看代码吧~ import axios from "axios"; import baseUrl from "../../setBaseUrl"; axios.defaults.baseURL = baseUrl; import { Loading, Message } from "element-ui"; const loadingOptions = { lock: true, text: "拼命加载中&q

  • 浅谈vue使用axios的回调函数中this不指向vue实例,为undefined

    今天在vue-cli脚手架搭建的项目中使用axios时,遇到无法解析this.$route的报错信息,最后发现是作用域的问题. 1.解决方法:使用 => 原代码: axios.get('/user', { params: { ID: 12345 } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); 修改为: axios.get('/u

  • 前端axios取消请求总结详解

    目录 应用场景 如何取消请求 项目中用法示例 批量取消请求 切换路由时,取消请求 取消请求的实现原理 应用场景 取消请求在前端有时候会用到,以下是两个工作中可能会用到的场景 tab切换时刷新某个列表数据,如果他们共用一个变量存储数据列表,当请求有延时,可能会导致两个tab数据错乱: 导出文件或下载文件时,中途取消 . 如何取消请求 取消http请求,axios文档里提供了两种用法: 第一种:使用 CancelToken const { CancelToken, isCanCel } = axio

  • node后端与Vue前端跨域处理方法详解

    目录 node.js后端跨域解决方案 前端vue项目 前端axios请求 node.js后端跨域解决方案 先看后端的入口文件: app.js const express = require('express'); const bodyParser = require('body-parser'); const cors = require('cors') const expressJWT = require('express-jwt') const app = express(); const

  • JSONP跨域请求实例详解

    JSOP简介 JSONP(JSON with Padding)是JSON的一种"使用模式",可用于解决主流浏览器的跨域数据访问的问题.由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的<script> 元素是一个例外.利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP.用 JSON

  • JS JSOP跨域请求实例详解

    在项目开发中遇到跨域的问题,一般都是通过JSONP来解决的.但是JSONP到底是个什么东西呢,实现的原理又是什么呢.在项目的空闲时间可以好好的来研究一下了. 1.什么是JSONP? 要了解JSONP,不得不提一下JSON,那么什么是JSON? JSON is a subset of the object literal notation of JavaScript. Since JSON is a subset of JavaScript, it can be used in the langu

  • vue全局使用axios的方法实例详解

    在vue项目开发中,我们使用axios进行ajax请求,很多人一开始使用axios的方式,会当成vue-resoure的使用方式来用,即在主入口文件引入import VueResource from 'vue-resource'之后,直接使用Vue.use(VueResource)之后即可将该插件全局引用了,所以axios这样使用的时候就报错了,很懵逼. 仔细看看文档,就知道axios 是一个基于 promise 的 HTTP 库,axios并没有install 方法,所以是不能使用vue.us

  • 基于form-data请求格式详解

    最近一直都比较忙,坚持月月更新博客的计划不得中止了,今天抽出点时间来说说最近项目中遇到的一个问题,有关request post请求格式中的multipart/form-data格式. 引言 最近在参与一个项目过程中遇到一个问题,相信大部分人都遇到过: 在后端与前端约定好application/json格式传递数据时,因为后台是go强类型语言,在定义api接口时,某些字段要求是整型类型,但是对于前端来说输入框或者从url中的search取到的参数都是字符串,不得不进行前端类型转换. 咋一看,对于接

  • Java Spring MVC获取请求数据详解操作

    目录 1. 获得请求参数 2. 获得基本类型参数 3. 获得POJO类型参数 4. 获得数组类型参数 5. 获得集合类型参数 6. 请求数据乱码问题 7. 参数绑定注解 @requestParam 8. 获得Restful风格的参数 9. 自定义类型转换器 1.定义转换器类实现Converter接口 2.在配置文件中声明转换器 3.在<annotation-driven>中引用转换器 10. 获得Servlet相关API 11. 获得请求头 11.1 @RequestHeader 11.2 @

  • Go类型安全的HTTP请求示例详解

    目录 前言 Go 原生写法 httpc 实现 更多能力 前言 对 Gopher 来说,虽然我们基本都是在写代码让别人来请求,但是有时候,我们也需要去请求第三方提供的 RESTful 接口,这个时候,我们才能感受到前端同学拼接 HTTP 请求参数的痛苦. 比如,我们要发起类似这样一个请求,看起来很简单,实际写起来还是比较繁琐的. POST /articles/5/update?device=ios HTTP/1.1 Host: go-zero.dev Authorization: Bearer <

  • SpringMVC请求数据详解讲解

    目录 一.RequestMapping注解 1.RequestMapping的属性 2.RequestMapping的请求参数绑定 二.RequestParam注解 三.RequestBody注解 四.RestFul风格 1.@PathVariable注解 2.使用method属性指定请求类型 一.RequestMapping注解 RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系 RequestMapping注解可以作用在方法和类上 作用在类上:第一级的访问目录 作

  • Python Flask前端自动登录功能实现详解

    目录 引言 1. 登录时 2. 定义全局拦截器 引言 在已有的网站中,几乎所有的网站都已经实现了 自动登录 所谓自动登录,其实就是在你登录后,然后关闭浏览器,接着再启动浏览器重新进入刚刚的网站时,无需自己再次登录.更准确的说,在一段时间内,无需自己再次登录 思路:其实所谓的自动登录,到最后的后端逻辑,和你正常的登录逻辑是一样的,也是判断用户名和密码是否正确.只是我们要省略让用户再次输入用户名和密码的步骤,那么肯定就要将用户名和密码存储在一个地方.当检测到用户再次进入时,看看是否满足可以自动登录的

随机推荐