axios架构设计和原理

news2025/4/27 16:34:35

1. 前端请求方式

  • 原生XHR:最初,在Web开发的早期,前端请求库的唯一选择是使用XMLHttpRequest(XHR)对象。XHR提供了一种在浏览器中发起HTTP请求的方式,但使用XHR需要编写大量重复的代码,并且缺乏灵活性
  • jQuery Ajax:随着jQuery的兴起,jQuery Ajax成为了主流的前端请求库。jQuery Ajax使用简单,可以轻松地发送异步请求,并且具有良好的跨浏览器支持。它为开发人员提供了简单易用的API,并支持各种数据格式,例如JSON和XML。
  • Fetch API:Fetch API是浏览器内置的一种用于发起HTTP请求的API,它支持Promise,更加简洁易用。Fetch API基于标准的Promise接口,可以更好地支持异步请求,从而提高代码的可读性和可维护性。
  • Axios:Axios是一个基于Promise的HTTP客户端库,它提供了简单、一致的API,可以轻松地处理HTTP请求和响应。Axios可以用于浏览器和Node.js,并且可以与React、Vue等框架很好地配合使用。它支持拦截请求和响应,支持取消请求等高级功能。

2. axios是什么

axios是一个基于promise的网络请求库,它可以用于浏览器和nodejs当中。在不同环境,它所使用的请求API是不同的,在nodejs环境使用的node原生的http模块,而在浏览器中使用的是XMLHTTPRequest

3. axios的特性

  • 从浏览器创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据
  • 客户端支持防御XSRF

4. axios的原理

axios整体架构:

在这里插入图片描述

4.1 axios的调用方式
// 第一种:直接调用
axios(config)
// 第二种:通过axios的属性方法调用
axios.get(url[, config])//'delete', 'get', 'head', 'options'请求方法一样的调用方式
axios.post(url[, data[, config]])// 'post', 'put', 'patch'请求方法永阳的调用方式

// 第三种:并行调用
axios.all([axios1, axios2, axios3]).then(axios.spread(function (axios1response, axios2response, axios3response) {
  // 三个请求现在都执行完成
}));
// 第四种:通过axios.create方法建立自定义全局默认配置的Axios实例
axios.create(config)
为什么 axios 既可以当函数调用,也可以当对象使用?
function createInstance(defaultConfig) {
  const context = new Axios(defaultConfig);
  const instance = bind(Axios.prototype.request, context);

  // Copy axios.prototype to instance
  utils.extend(instance, Axios.prototype, context);

  // Copy context to instance
  utils.extend(instance, context, null);

  // Factory for creating new instances
  instance.create = function create(instanceConfig) {
    return createInstance(mergeConfig(defaultConfig, instanceConfig));
  };

  return instance;
}

// Create the default instance to be exported
const axios = createInstance(defaults);

axios.create = function create(instanceConfig) {
  return createInstance(mergeConfig(axios.defaults, instanceConfig));
};

axios.all = function all(promises) {
  return Promise.all(promises);
};

axios.spread = function (callback) {
  return function wrap(arr) {
    return callback.apply(null, arr);
  };
}
export default axios

axios类:

class Axios {
  constructor(instanceConfig) {
    this.defaults = instanceConfig;
    this.interceptors = {
      request: new InterceptorManager(),
      response: new InterceptorManager()
    };
  }
  request(configOrUrl, config) {
    /*eslint no-param-reassign:0*/
    // Allow for axios('example/url'[, config]) a la fetch API
    if (typeof configOrUrl === 'string') {
      config = config || {};
      config.url = configOrUrl;
    } else {
      config = configOrUrl || {};
    }

    config = mergeConfig(this.defaults, config);
    // ....省略了一些代码
    
  }
}

utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
  Axios.prototype[method] = function(url, config) {
    return this.request(mergeConfig(config || {}, {
      method,
      url,
      data: (config || {}).data
    }));
  };
});
4.2 axios的拦截器

拦截器的使用:

// 请求拦截器
const requestInterceptor = axios.interceptors.request.use(config => {
    return config;
}, error => {
    return Promise.reject(error);
});

// 添加响应拦截器
const responseInterceptor = axios.interceptors.response.use(response => {
  return response;
}, error => {
  return Promise.reject(error);
});

// 移除拦截器
axios.interceptors.request.eject(requestInterceptor);

多个拦截器:
在这里插入图片描述

执行顺序:

  • 请求拦截器:先添加的后执行
  • 响应拦截器:先添加的先执行

拦截器的原理:

  1. 存储拦截器
class InterceptorManager {
  constructor() {
    this.handlers = [];
  }

  use(fulfilled, rejected, options) {
    this.handlers.push({
      fulfilled,
      rejected
    });
    return this.handlers.length - 1;
  }
  eject(id) {
    if (this.handlers[id]) {
      this.handlers[id] = null;
    }
  }
}

export default InterceptorManager;
  1. 建立promise链
class Axios {
  constructor() {
    this.interceptors = {
      request: new InterceptorManager(),
      response: new InterceptorManager()
    }
  }
  request(config) {
        const chain = [{
            onFulfilled: this.dispatchRequest,
            onRejected: null
        }]
        this.interceptors.request.interceptors.forEach((interceptor) => {
            interceptor && chain.unshift(interceptor)
        })

        this.interceptors.response.interceptors.forEach((interceptor) => {
            interceptor && chain.push(interceptor)
        })
        let promise = Promise.resolve(config);

        while (chain.length) {
            const { onFulfilled, onRejected } = chain.shift()!;
            promise = promise.then(onFulfilled, onRejected);
        }
        return promise
    }
}
4.3 cancelToken取消请求

取消请求用法:

// 第一种取消方法
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 {
    // handle error
  }
});

source.cancel('Operation canceled by the user.');

// 第二种取消方法
const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // An executor function receives a cancel function as a parameter
    cancel = c;
  })
});

// cancel the request
cancel();

取消请求实现:

export class Cancel {
    constructor(public reason: string) { }
}
export function isCancel(error: any) {
    return error instanceof Cancel;
}
export class CancelToken {
    public resolve: any;
    source() {
        return {
            token: new Promise((resolve) => {
                this.resolve = resolve;
            }),
            cancel: (reason: string) => {
                this.resolve(new Cancel(reason));
            }
        }
    }
}

// axios.js
axios.CancelToken = new CancelToken();
axios.isCancel = isCancel;

function dispatchRequest(config){
  // 发送xhr请求
   if (config.cancelToken) {
       config.cancelToken.then((reason: string) => {
          request.abort();
          reject(reason);
      });
   }
}

5. 其它请求库

umi-request,基于 fetch 封装, 兼具 fetch 与 axios 的特点, 旨在为开发者提供一个统一的 api 调用方式, 简化使用, 并提供诸如缓存, 超时, 字符编码处理, 错误处理等常用功能.

umi-request和fetch和axios的对比:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2281862.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络安全 | 入侵检测系统(IDS)与入侵防御系统(IPS):如何识别并阻止威胁

网络安全 | 入侵检测系统(IDS)与入侵防御系统(IPS):如何识别并阻止威胁 一、前言二、入侵检测系统(IDS)2.1 IDS 的工作原理2.2 IDS 的技术类型2.3 IDS 的部署方式 三、入侵防御系统(…

idea修改模块名导致程序编译出错

本文简单描述分别用Idea菜单、pom.xml文件管理项目模块module 踩过的坑: 通过idea菜单创建模块,并用idea菜单修改模块名,结构程序编译报错,出错的代码莫名奇妙。双击maven弹窗clean时,还是报错。因为模块是新建的&am…

【2024年终总结】深圳工作生活评测

距离上次写年终总结已经过了一年半了,这一年半中哪怕经历了很多的事情,但是感觉又没发生什么。想写一些骚话,却总觉得自己无法完全表达,便也就这样,静静地记录下这一段时光。 现在是2025年,春节前的时光&am…

如何设计浪漫风格的壁纸

一、选择浪漫的色彩 柔和色调: 粉色系:粉色是浪漫的经典色彩,包括淡粉色、玫瑰粉、樱花粉等,能够营造出温馨和甜蜜的氛围。 紫色系:紫色带有神秘和高贵的感觉,如薰衣草紫、淡紫色等,适合营造浪…

element el-table合并单元格

合并 表格el-table添加方法:span-method"” <el-table v-loading"listLoading" :data"SHlist" ref"tableList" element-loading-text"Loading" border fit highlight-current-row :header-cell-style"headClass" …

【unity游戏开发之InputSystem——07】InputSystem+UGUI配合使用(基于unity6开发介绍)

文章目录 一、InputSystem+UGUI配合使用1、官方文档参考2、切换到新的输入模块二、UGUI中的新输入系统输入模块参数相关1、Send Pointer Hover To Parent2、Move Repeat Delay3、Move Repeat Rate4、XR Tracking Origin5、Deselect On Background CLick6、Pointer Behavior7、S…

web端ActiveMq测试工具

如何用vue3创建简单的web端ActiveMq测试工具&#xff1f; 1、复用vue3模板框架 创建main.js,引入APP文件&#xff0c;createApp创建文件&#xff0c;并加载element插件&#xff0c;然后挂载dom节点 2、配置vue.config.js脚本配置 mport { defineConfig } from "vite&qu…

2K高刷电竞显示器推荐

2K高刷电竞显示器推荐&#xff0c;各位喜欢打游戏&#xff0c;身为电竞迷的小伙伴&#xff0c;如果你想选一款2K高刷电竞显示器&#xff0c;那么下面的内容不容错过。 1.HKC G27H4Pro - 2K高刷电竞显示器推荐 外观 - HKC G27H4Pro 2K高刷电竞显示器 初见 HKC G27H4Pro&#x…

他把智能科技引入现代农业领域

江苏田倍丰农业科技有限公司&#xff08;以下简称“田倍丰”&#xff09;是一家专注于粮油种植的农业科技公司&#xff0c;为拥有300亩以上田地的大户提供全面的解决方案。田倍丰通过与当地政府合作&#xff0c;将土地承包给大户&#xff0c;并提供农资和技术&#xff0c;实现利…

第38周:猫狗识别 (Tensorflow实战第八周)

目录 前言 一、前期工作 1.1 设置GPU 1.2 导入数据 输出 二、数据预处理 2.1 加载数据 2.2 再次检查数据 2.3 配置数据集 2.4 可视化数据 三、构建VGG-16网络 3.1 VGG-16网络介绍 3.2 搭建VGG-16模型 四、编译 五、训练模型 六、模型评估 七、预测 总结 前言…

OpenCV2D 特征框架 (6)特征检测与描述类cv::KAZE的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::KAZE 类是 OpenCV 库中用于实现 KAZE 特征检测和描述的类。KAZE 是一种尺度不变特征变换&#xff08;Scale-Invariant Feature Transform, S…

Unity git版本管理

创建仓库的时候添加了Unity的.gitignore模版&#xff0c;在这个时候就能自动过滤不需要的文件 打开git bash之后&#xff0c;步骤git版本管理-CSDN博客 如果报错&#xff0c;尝试重新进git 第一次传会耗时较长&#xff0c;之后的更新就很快了

Neural networks 神经网络

发展时间线 基础概念 多层神经网络结构 神经网络中一个网络层的数学表达 TensorFlow实践 创建网络层 神经网络的创建、训练与推理 推理 推理可以理解为执行一次前向传播 前向传播 前向传播直观数学表达 前向传播直观数学表达的Python实现 前向传播向量化实现 相关数学知识…

2023年吉林省职业院校技能大赛网络系统管理样题

目录 任务清单 &#xff08;一&#xff09;基础配置 &#xff08;二&#xff09;有线网络配置 &#xff08;三&#xff09;无线网络配置 &#xff08;四&#xff09;出口网络配置 附录1&#xff1a;拓扑图​编辑 附录2&#xff1a;地址规划表 任务清单 &#xff08;一&a…

C++入门14——set与map的使用

在本专栏的往期文章中&#xff0c;我们已经学习了STL的部分容器&#xff0c;如vector、list、stack、queue等&#xff0c;这些容器统称为序列式容器&#xff0c;因为其底层是线性序列的数据结构&#xff0c;里面存储的是元素本身。而本篇文章我们要来认识一下关联式容器。 &am…

996引擎 - 前期准备-配置开发环境

996引擎 - 前期准备 官网搭建服务端、客户端单机搭建 开发环境配置后端开发环境配置环境 前端开发环境配置环境 后端简介前端简介GUILayoutGUIExport 官网 996传奇引擎官网 所有资料从官网首页开始&#xff0c;多探索。 文档&#xff1a; 996M2-服务端Lua 996M2-客户端Lua 搭…

Java程序员如何设计一个高并发系统?

前言 无论是职场新人还是有一定工作经验的老手&#xff0c;系统设计问题都如同悬在头顶的达摩克利斯之剑。对于新人而言&#xff0c;面试时遭遇“如何从零开始设计一个完整系统”的问题&#xff0c;往往让人瞬间大脑一片空白。系统设计的范畴广泛&#xff0c;网络资源难以全面…

RV1126画面质量三:QP调节

一&#xff0e;什么是 QP 调节&#xff1f; QP 参数调节&#xff0c;指的是量化参数调节。它主要是来调节图像的细节&#xff0c;最终达到调节画面质量的作用。QP 值和比特率成反比&#xff0c;QP值越小画面质量越高&#xff1b;反之 QP 值越大&#xff0c;画面质量越低…

渐变颜色怎么调?

渐变颜色的调整是设计中非常重要的一部分&#xff0c;尤其是在创建具有视觉吸引力和深度感的设计作品时。以下是一些在不同设计软件中调整渐变颜色的详细步骤和技巧&#xff1a; 一、Adobe Photoshop 1. 创建渐变 打开渐变工具&#xff1a; 选择工具栏中的“渐变工具”&#x…

Arduino基础入门学习——OLED显示屏的基本使用

Arduino基础入门学习——OLED显示屏的基本使用 一、前言二、准备工作三、基本使用1. OLED显示基本字符 &#xff08;数字英文基本标点符号&#xff09;2. OLED显示汉字3. 显示图片 四、 结束语 一、前言 在我们的日常开发中&#xff0c;一般有这么几种方式对数据进行展示&#…