web开发中如何优雅的解决"重复请求"问题

目录
  • 前言
  • 提出问题
  • 解决思路
  • axios 如何取消请求
  • 封装axios
    • 准备工作
    • 开始封装
  • 总结

前言

在我们web开发过程中,很多地方需要我们取消重复的请求。但是哪种场合需要我们取消呢?我们如何取消呢?带着这些问题我们阅读本文。

阅读完本文,你将了解以下内容:

需要取消重复请求的场景

我们如何取消重复请求

axios如何取消重复的请求

封装axios

如何给开源的项目提供源码

如何在本地调试npm包

提出问题

最近做的项目中,用的用户经常遇到这样的问题:

  • 用户频繁切换筛选条件去请求数据,初次的筛选条件数据量大。用的时间比较多。后面的筛选条件的数据量小。导致后面请求的数据先返回。内容先显示在页面上。但是等一段时间,初次(或者前面)的请求数据返回了, 会覆盖后面的请求的数据。这就导致了筛选条件和内容不一致的情况。
  • 用户点击了一次提交按钮,接口没有很快响应,导致页面没办法做逻辑语句判断的提示。用户觉得可能没提交上,便会快速又点了按钮几次。如果后端没有去重的判断,就会导致数据中有很多条重复的数据。

这些问题给用户的体验是很不友好的。那么取消无用的请求是很有必要的。

解决思路

我们用的请求库是axios。那么我们可以在请求的时候拦截请求判断当前的请求是否重复,如果重复我们就取消当前的请求。大致的实现过程如下:

我们把目前处于pending的请求存储(假如我们放在一个数组)起来。每个请求发送之前我们都要判断当前这个请求是否已经存在于这个数组。如果存在,说明请求重复了,我们就在数组中找到重复的请求并且取消。如果不存在,说明这个请求不是重复的,正常发送并且把这个请求api添加在数据中,等请求结束之后删除数组中的这个api。

我们这个解决思路有了,但是axios如何取消请求的呢?我们先来了解下

axios 如何取消请求

查看axios文档发现axios提供了两种取消请求的方法(http://www.axios-js.com/zh-cn/docs/#%E5%8F%96%E6%B6%88)

第一种方法

通过axios.CancelToken.source生成取消令牌token和取消方法cancel

const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // 处理错误
  }
});
axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})
// 取消请求 (消息参数是可选的)
source.cancel('Operation canceled by the user.');

第二种方式

通过传递一个 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();

封装axios

解决取消请求的思路有了,取消请求的办法也有了,那么剩下的就是封装了

由于同事之前已经封装了axios——very-axios(https://github.com/verymuch/very-axios) (基于 axios 进行二次封装,更简单、更统一地使用 axios)。那么我们就这个基础上提一个pr吧。那么从现在开始我们就一步一步的来实现,这个过程包含了【如何给开源的项目贡献代码】【如何在本地调试npm】如果已经了解的同学可以直接略过。

准备工作

由于同事已经封装了axios并且已经开源了。那么我贡献代码的方式主要有两种:

  • 代码仓库的管理者给我们添加这个仓库的写入权限,如果这样,我们就可以直接提push。
  • 如果我们没有权限(大多数情况)。我们使用经典的fork & pull request 的方式来提交代码。

我们采用的第二种方式。我们去 very-axios(https://github.com/verymuch/very-axios) 把代码fork到自己的仓库(如果你还没有自己的github,需要自己注册下哦)。

那么你回到自己的github仓库下面就会看有一个一摸一样的项目

那么我们现在就可以git clone这个仓库的代码到本地,新建branch进行开发,就比如我新建了一个这样的branch:

现在已经有本地的代码了,但是我们如何本地化调试npm包呢?那就需要npm link 了

首先在我们要修改的npm 包中npm link:

之后我们会得到

/Users/shuliqi/.nvm/versions/node/v12.17.0/lib/node_modules/very-axios -> /Users/shuliqi/study/axios/very-axios

这意思就是我们把very-axios链接到全局的node_modules

然后我们进入我们my-project-of-axios 目录下面执行npm link very-axios 如图:

这意思就是very-axios被安装在my-project-of-axios 下面了。very-axios的修改都会同步到my-project-of-axios。就实现本地测试了。

我们在my-project-of-axios中的HelloWorld.vue文件中做列子。

如果这里看的不是很懂的同学可以看看这两篇文章:如何在本地调试npm包(https://github.com/allenGKC/Blog/issues/13)。如何使用 GitHub Flow 给开源项目贡献代码(https://juejin.im/post/6844903636863041550)

开始封装

准备工作完成了, 那我们开始封装的事情。根据我们之前的思路。我们采用axios 如何取消请求的第一种方式。

声明一个Map。用来存储每个请求的 标识 和 取消的函数

// 存储每个请求的标识和取消的函数
this.pendingAjax = new Map();

自定一个字段来让用户自己决定是否需要取消重复的请求

// 是否取消重复的请求
cancelDuplicated = false,

自定一个字段来让用户是否有全局的统一的设置重复标识的函数。如果没有设置全局的统一的函数,则默认是请求的method 和url作为重复的标识

// 生成重复标识的方式
duplicatedKeyFn,
this.duplicatedKeyFn = isFunction(duplicatedKeyFn) ? duplicatedKeyFn : (config) => `${config.method}${config.url}`;

添加请求

/**
 * 将请求添加到pendingAjax
 * @param {Object} config
 */
addPendingAjax(config) {
  // 是否需要取消重复的请求
  if (!this.cancelDuplicated) return
  const veryConfig = config.veryConfig || {};
  const duplicatedKey = JSON.stringify({
    duplicatedKey: veryConfig.duplicatedKey || this.duplicatedKeyFn(config),
    type: REQUEST_TYPE.DUPLICATED_REQUEST,
  });
  config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
    // 如果pendingAjax中不存在当前请求,添加进去
    if (duplicatedKey && !this.pendingAjax.has(duplicatedKey)) {
      this.pendingAjax.set(duplicatedKey, cancel);
    }
  });
}

这里面我们可以使用duplicatedKey字段来让用户对单一请求自定义重复的标识。或者可以使用一个函数duplicatedKeyFn统一的让用户自定义重复的标识

删除请求

/**
   * 从pendingAjax中删除请求
   * @param {Object} config
   */
  removePendingAjax(config) {
    // 是否需要取消重复的请求
    if (!this.cancelDuplicated) return
    const veryConfig = config.veryConfig || {};
    const duplicatedKey = JSON.stringify({
      duplicatedKey: veryConfig.duplicatedKey || this.duplicatedKeyFn(config),
      type: REQUEST_TYPE.DUPLICATED_REQUEST,
    });
    // 如果pendingAjax中存在当前请求, 取消当前请求并将其删除
    if (duplicatedKey && this.pendingAjax.has(duplicatedKey)) {
      const cancel = this.pendingAjax.get(duplicatedKey);
      cancel(duplicatedKey);
      this.pendingAjax.delete(duplicatedKey);
    }
  }

封装好了, 我们在哪里使用呢?肯定是在请求开始之前和请求完成之后使用。

在请求之前

// 拦截请求
this.axios.interceptors.request.use((config) => {
  // 在请求开始之前检查先前的请求
  this.removePendingAjax(config);
  // 将当前请求添加到pendingAjax
  this.addPendingAjax(config);
  // ...
});

在请求完成之后去掉该请求

// 拦截响应
this.axios.interceptors.response.use(response => {
  removePending(response)
  return response
}, error => {
  // ...
})

到现在已经完成了该有的功能, 但是取消请求的错误我们不该返回给用户。所以:

(err) => {
// 类型是否为重复请求
let isDuplicatedType;
try {
  const errorType = (JSON.parse(error.message) || {}).type
  isDuplicatedType = errorType === REQUEST_TYPE.DUPLICATED_REQUEST;
} catch (error) {
  isDuplicatedType = false
}
if (isDuplicatedType) return;
}

我们在请求完成之后的err里面做一个判断,判断如果当前请求是取消的类型,我们就不返回给用户错误的提示信息。

总结

至此,完成了我们的封装。完成的pr地址:(https://github.com/verymuch/very-axios/pull/1)。本文测试npm包的项目地址:(https://github.com/shuliqi/my-project-of-axios)

到此这篇关于web开发中如何优雅的解决"重复请求"问题的文章就介绍到这了,更多相关axios取消重复请求内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • axios如何取消重复无用的请求详解

    前言 在开发中,经常会遇到接口重复请求导致的各种问题. 对于重复的get请求,会导致页面更新多次,发生页面抖动的现象,影响用户体验. 对于重复的post请求,会导致在服务端生成两次记录(例如生成两条订单记录). 如果当前页面请求还未响应完成,就切换到了下一个路由,那么这些请求直到响应返回才会中止. 无论从用户体验或者从业务严谨方面来说,取消无用的请求确实是需要避免的. 当然我们可以通过页面loading来避免用户进行下一次的操作,但本文只讨论单纯的如何取消这些无用的请求. axios 的 can

  • 详解Axios 如何取消已发送的请求

    前言 最近在项目中遇到一个问题,在连续发送同一请求时,如果第二次请求比第一次请求快,那么实际显示的是第一次请求的数据,这就会造成数据和我选择的内容不一致的问题.解决的方案:在后续发送请求时,判断之前的请求是否完成(同一个接口),如果未完成则立即取消.然后在发送新的请求. Axios 介绍 Axios是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中. Axios 使用 cancel token 取消请求 Axios的 cancel token API 基于canc

  • axios取消请求的实践记录分享

    问题的来源 用el-autocomplete远程获取数据时,点击输入框会触发第一次请求,然后输入搜索文字后会触发第二次请求,两次请求间隔较短,有时候会出现第二次请求比第一次请求先返回的情况,导致我们期望的第二次发送的请求返回的数据会被第一次请求返回的数据覆盖掉 解决思路 在发送第二次请求的时候如果第一次请求还未返回,则取消第一次请求,以保证后发送的请求返回的数据不会被先发送的请求覆盖. axios官方文档取消请求说明 方法一: const CancelToken = axios.CancelTo

  • axios取消请求与避免重复请求

    目录 起源 现状 取消请求 cancelToken 修改后的请求方法 避免重复请求 总结 起源 某个页面需要下载全部数据的功能,下载数据量大,接口延迟长..... 某个页面加载初始数据量延长长,但单个检索快速,出现初始数据加载中时,检索接口返回,初始数据后续返回覆盖了检索数据的展示.... 这些情况需要我们: 能够手动取消/终止请求Request. 某些页面接口同时只能有一个在请求. 现状 系统基于老哥花裤衩开源的vue-element-admin做的二次开发,其中的请求采用的是axios,其中

  • Axios取消重复请求的方法实例详解

    目录 前言 一.如何取消请求 二.如何判断重复请求 三.如何取消重复请求 3.1 定义辅助函数 3.2 设置请求拦截器 3.3 设置响应拦截器 四.CancelToken 的工作原理 五.总结 六.参考资源 前言 在 Web 项目开发过程中,我们经常会遇到重复请求的场景,如果系统不对重复的请求进行处理,则可能会导致系统出现各种问题.比如重复的 post 请求可能会导致服务端产生两笔记录.那么重复请求是如何产生的呢?这里我们举 2 个常见的场景: 假设页面中有一个按钮,用户点击按钮后会发起一个 A

  • web开发中如何优雅的解决"重复请求"问题

    目录 前言 提出问题 解决思路 axios 如何取消请求 封装axios 准备工作 开始封装 总结 前言 在我们web开发过程中,很多地方需要我们取消重复的请求.但是哪种场合需要我们取消呢?我们如何取消呢?带着这些问题我们阅读本文. 阅读完本文,你将了解以下内容: 需要取消重复请求的场景 我们如何取消重复请求 axios如何取消重复的请求 封装axios 如何给开源的项目提供源码 如何在本地调试npm包 提出问题 最近做的项目中,用的用户经常遇到这样的问题: 用户频繁切换筛选条件去请求数据,初次

  • Django Web开发中django-debug-toolbar的配置以及使用

    前言 django,web开发中,用django-debug-toolbar来调试请求的接口,无疑是完美至极. 可能本人,见识博浅,才说完美至极, 大神,表喷,抱拳了. django_debug_toolbar 是django的第三方工具包,给django扩展了调试功能. 包括查看执行的sql语句,db查询次数,request,headers,调试概览等. django-debug-toolbar的配置方法如下 第一步: pip install django-debug-toolbar 安装完成

  • Web 开发中Ajax的Session 超时处理方法

    在 Java Web 开发中,当session超时的情况下,普通页面的跳转好处理.关于Ajax的请求超时处理,就需要特殊处理下了. 先写一个统一的过滤器,或者拦截器,针对Ajax请求进行过滤处理,下面示例以Filter为例: public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServ

  • Web开发中客户端的跳转与服务器端的跳转的区别

    客户端的跳转:跳转之后地址栏的信息是会变的,变为跳转之后的地址信息 例如:response.sendRedirect(); 服务器端的跳转:跳转之后的地址栏的信息不会发生任何的改变 例如:<jsp:forword> request.getRequestDisPather("").forword(request, response); (1).而且在使用request属性范围时,只有服务器端跳转才能将request范围的属性保存到跳转页面:而如果是客户端的跳转,则无法进行re

  • web开发中添加数据源实现思路

    在web开发中,可以利用hibernate配置数据源,但在实际的应用中,可能要连接多个数据源, 1.配置dataSource <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"> <value>org.logicalc

  • java web开发中大量数据导出Excel超时(504)问题解决

    import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; impo

  • Android开发中的错误及解决办法总结

    目录 一 概述 二 错误类 2.1 Cannot inline bytecode built with JVM target 1.8 2.2 Unable to find EOCD signature 2.3 failed to read PNG signature: file does not start with PNG signature 2.4 Android Gradle plugin requires Java 11 to run. You are currently using J

  • Java Web开发中过滤器和监听器使用详解

    目录 1 Filter 1.1 Filter简介 1.2 Filter的快速入门 1.2.1 创建Filter类 1.2.2 访问index.jsp 1.3 Filter的拦截路径的配置 1.4 过滤器链 1.4.1 过滤器链简介 1.4.2 过滤器链的例子 2 Listener 2.1 概念 2.2 监听器的使用 1 Filter 1.1 Filter简介 Filter表示过滤器,是JavaWeb三大组件(Servlet.Filter.Listener)之一. 过滤器可以把资源的请求拦截下来,

  • 自定义事件解决重复请求BUG的问题

    现在,组件化开发还是比较流行的,毕竟其优点相当突出.最近在开发一个组件的时候,遇到了一个很有意思的BUG... BUG的背景 最近在开发一个组件,好不容易开发好了转测试.然后,测试给我提了一个这样的bug,orz... 因为是一个组件,最大的好处就是可以随处复用,随处使用,然而,当一个页面用了多个组件,只有最后一个生效的时候,这个组件就没有什么意义了... BUG原因查找 这个组件的初始数据来源的接口是固定的,也就是说,页面内的所有这个组件在初始化的时候都会发出同样的请求,这里的请求是jsonp

  • 对Web开发中前端框架与前端类库的一些思考

    说起前端框架,我也是醉了.现在去面试或者和同行聊天,动不动就这个框架碉堡了,那个框架好犀利. 当然不是贬低框架,只是有一种杀鸡焉用牛刀的感觉.网站技术是为业务而存在的,除此毫无意义,框架也是一样.在技术选型和架构设计当中,脱离网站业务发展的实际,一味的追求时髦新技术,可能会适得其反,将网站发展引入崎岖小道.就好像一个日均pv只有几百的小型电商网站,却要大喊"某宝就是这么搞的",然后搭建应用服务器集群,使用分布式文件系统和分布式数据库系统...等巴拉巴拉的一堆用来处理高并发,海量数据访问

随机推荐