Axios 应用: 实现后端接口封装 重复请求回避(撤销请求)

news/2024/7/19 15:05:01 标签: js, axios, cancelToekn

Axios 应用: 实现后端接口封装 & 重复请求回避(撤销请求)

文章目录

  • Axios 应用: 实现后端接口封装 & 重复请求回避(撤销请求)
    • 简介
    • 参考
    • 完整示例代码
  • 正文
    • 目标
    • axios 中的请求撤销
      • 1. CacelToken.source 工厂方法
      • 2. CancelToken 构造函数(参数为接受一个 cancel 方法的回调)
    • 代码示例
      • axios 对象封装
      • 后端 API 封装
      • 测试
  • 结语

简介

之前的Axios:前端 HTTP 請求介绍了 js 的第三库 Axios,封装前端 AJAX 请求的 API 和详细的使用参数。但是相信大部分的人,包括正在做项目而需要直接上手的开发者,肯定没有耐心也没有时间细细的品味哪些参数能用在哪里。

因此本篇将要从封装后端 API 接口以及实现避免多次点击的重复请求问题的角度进行整理,为大家提供一种 Axios 的使用模型,相当于是对 Axios 进行再封装,马上来看看。

参考

axios中的取消请求https://www.cnblogs.com/yancyzheng/p/12576329.html

完整示例代码

https://github.com/superfreeeee/Blog-code/tree/main/front_end/others/axios-encapsulation

正文

目标

首先我们先明确接下来要完成的模型目标:

  1. 封装 axios 和后端的接口,使用者不需要自行管理 axios 相关配置,能专注在业务数据上
  2. 限制重复的 http 请求,短时间内发起相同请求则撤销前一次请求(重复触发的逻辑可根据业务需要进行更改)

axios__32">axios 中的请求撤销

在开始实现 axios 的再封装之前,我们先来搞清除 axios 提供的撤销请求的接口有哪些

1. CacelToken.source 工厂方法

第一种是使用 axios.CancelToken 提供的工厂方法 source 生成一个 cancelToken,并可透过 cancel 方法来撤销请求

js">import axios from 'axios'
const CancelToken = axios.CancelToken

// 生成 cancelToekn 实例
const source = CancelToken.source()

axios.get('/xxx/yyy', {
    cancelToken: source.token
}).catch((err) => {
    if (axios.isCancel(err)) {
        console.log('Request cancel')
    } else {
        // 其他错误处理
        // 例:return Promise.reject(err)
    }
})

2. CancelToken 构造函数(参数为接受一个 cancel 方法的回调)

第二种则是直接使用 CancelToken 的构造函数,参数为一个回调函数,回调函数接受一个 cancel 方法作参数

js">import axios from 'axios'
const CancelToken = axios.CancelToken

let cancel

axios.get('/xxx/yyy', {
    cancelToken: new CancelToken((c) => {
        // c 为该请求对应的撤销函数
        cancel = c
    })
})

// 撤销请求
cancel()

代码示例

好了了解了 axios 的撤销请求方法之后,就能够开始我们的项目用 axios 再封装了。完整的示例项目实现请到完整示例代码,这边只列出关键的核心代码。

axios__84">axios 对象封装

首先第一步我们要创建自己的 axios 对象,取代全局 axios 对象作为我们的请求主体

js">/* axios.js */
import axios from 'axios'

const CancelToken = axios.CancelToken

const instance = axios.create({
  baseURL: 'http://localhost:3000',
  timeout: 10000,
})

// 请求中队列
const requests = []

// 撤销请求
const cancelRequest = (config) => {
  const target = `${config.url}&${config.method}`
  for (let idx in requests) {
    if (requests[idx].umet === target) {
      requests[idx].cancel(`撤销请求: ${target}`)
      requests.splice(idx, 1)
    }
  }
}

// 请求拦截器
instance.interceptors.request.use(
  (config) => {
    config.headers = {
      'content-type': 'application/json; charset=utf-8',
    }
    cancelRequest(config)
    config.cancelToken = new CancelToken((c) => {
      requests.push({ umet: `${config.url}&${config.method}`, cancel: c })
    })
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

// 响应拦截器
instance.interceptors.response.use(
  (response) => {
    cancelRequest(response.config)
    return response.data
  },
  (error) => {
    return Promise.reject(error)
  }
)

export default instance
  1. 首先第一步我们使用 axios.create 创建新的 axios 实例(通常如果整个前端需要请求多个后端服务,可以考虑不设置 baseUrl;或是选择为每个服务端创建一个专用的 axios 实例)
  2. 设置请求中队列(requests)撤销请求的函数(cancelRequest)
  3. 设置请求/响应的拦截器:请求时先撤销前一次相同的请求,并设置新的 cancelToekn;响应时删除对应的撤销函数
  4. 最后返回我们自己创建的 axios 实例 instance,不使用全局的 axios 实例

后端 API 封装

在封装后端 API 的时候通常我们可以将不同业务(好的命名风格应该按前缀划分)分装在不同的文件之下,并对每个后端方法进行对应的封装

  • 后端接口
js">app.get('/test/1', (req, res, next) => {
  setTimeout(() => {
    res.send(`response1: ${new Date()}`)
  }, 3000)
})

app.get('/test/2', (req, res, next) => {
  setTimeout(() => {
    res.send(`response2: ${new Date()}`)
  }, 3000)
})

后端接口的实现我们使用 express 简单实现,并设定适当的延迟方便测试的时候进行重复请求。下面我们就可以针对后端的接口进行对应的封装

js">/* testAPI.js */
import axios from './axios.js'

const prefix = '/test'

function queryParamToStr(obj = {}) {
  const params = []
  for (let prop in obj) {
    params.push(`${prop}=${obj[prop]}`)
  }
  return params.join('&')
}

export function test1API(queryParam) {
  const queryStr = queryParamToStr(queryParam)
  return axios({
    url: `${prefix}/1?${queryStr}`,
    method: 'GET',
  })
}

export function test2API(queryParam) {
  const queryStr = queryParamToStr(queryParam)
  return axios({
    url: `${prefix}/2?${queryStr}`,
    method: 'GET',
  })
}

除了对后端接口进行封装之外,还另外设置了一个用于处理查询参数的方法,使得调用接口的时候能传入简单对象而不需要自己组装成 query 参数

测试

最后给出调用代码和测试结果输出

js">/* index.js */
import { test1API, test2API } from './api/test.js'

document.getElementById('btn-test1').addEventListener('click', (e) => {
  console.log('click test1')
  test1API().then(res => {
    console.log(res)
  })
})
document.getElementById('btn-test2').addEventListener('click', (e) => {
  console.log('click test2')
  test2API().then(res => {
    console.log(res)
  })
})

首先我们先分别执行一次两个请求的正常调用,之后再连续请求两次第一个接口,我们可以看到第二次重复调用第一个接口之后撤销了一次,并且最后只返回一次结果,大功告成!

结语

本篇实现了对 axios 进一步的封装,以及重复请求的避免。然而在实际业务场景之下我们还可以透过使用其他手段来避免重复请求,例如:点击按钮后取消事件监听、请求状态跟踪等,需要根据具体的业务目标和需要作调整,这边提供的是一种根据 axios 提供的接口(CancelToekn 对象)和拦截器(interceptors)来实现的,供大家参考。


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

相关文章

BungeeNeRF/CityNeRF ECCV2022

蓝色 紫色 红色 BungeeNeRF: Progressive Neural Radiance Field for Extreme Multi-scale Scene Rendering Author From : Abstract NeRF在 单尺度场景下 的三维物体和可控场景建模下取得优异表现。本文聚焦于多尺度场景,在截然不同的尺度上观察到的…

设计模式: Mediator 中介者模式

设计模式: Mediator 中介者模式 文章目录设计模式: Mediator 中介者模式简介参考完整示例代码正文场景模式结构代码实现:文字对话框Widgets 窗口组件DialogDirector 对话框导向器测试结语模式特点简介 目的创建型结构型行为型类Factory Method 工厂方法Adapter 适配…

第一章计算机基础学习笔记

笔记整理起始时间:2018年3月29日11:19:17章节导航1.计算机系统2.计算机硬件组成3.操作系统4.Linux相关介绍5.Linux哲学思想6.获取Linux7.虚拟机1.计算机系统定义:计算机(computer),俗称电脑,是一种能接受和…

Deblur-NeRF CVPR 2022

蓝色 紫色 红色 Deblur-NeRF: Neural Radiance Fields from Blurry Images Author From: Abstract 神经辐射场(NeRF)由于其显著的合成质量,在三维场景重建和新视图合成方面获备受关注。然而,在野外捕捉场景时经常发生由 散焦或运…

ADT: Red-Black Tree 红黑树详解(附完整实现)

ADT: Red-Black Tree 红黑树详解(附完整实现) 文章目录ADT: Red-Black Tree 红黑树详解(附完整实现)简介参考完整示例代码正文红黑树的前身今世从 BST 到 AVL从 AVL 到 RB-Tree红黑树的规则代码实现操作接口Color 颜色定义 & Node 节点结构 & 初始化工具方法Rotate 旋转…

百度AI的图像处理SDK使用

百度智能云平台 1. 创建想要使用的应用 2. 可以选择在线调用或者离线装载SDK 3. 参考所选应用的使用手册调整代码 使用百度API进行人像分割 官方使用说明:人像分割 import argparse import cv2 import base64 import numpy as np import time import os from …

jquery自带的进度条功能如何使用?

弹出进度条:先做弹出的功能modal,再做进度条显示。在弹出的界面上增加进度条功能 1 $.ajax({2 xhr: function()3 {4 var xhr new window.XMLHttpRequest();5 6 //Upload progress7 xhr.upload.addEventListener("progress&quo…

Java 踩坑笔记: YYYY-MM-dd 的误用

Java 踩坑笔记: YYYY-MM-dd 的误用 文章目录Java 踩坑笔记: YYYY-MM-dd 的误用简介参考完整示例代码正文测试代码问题来源结语简介 可能对于熟悉 java 的开发者来说已经是老生常谈了,本篇将要来说说在 SimpleDateFormat 中使用 YYYY-MM-dd 可能会带来的问题。 参考…