一文深度剖析Axios源码

本文详细剖析了Axios的源码,从整体代码结构、执行流程到具体执行文件的分析,涵盖Axios的主要特性、拦截器实现和数据处理。通过对axios的request、InterceptorManager、dispatchRequest等关键部分的解读,揭示了其内部工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文概要

  • 前言

  • Axios整体代码结构分析

  • Axios执行流程整体分析

  • Axios执行文件分析

前言

axios 是目前最常用的 http 请求库,可以用于浏览器和 node.js , 在 github 上已有 43k star 左右之多。

Axios 的主要特性包括:

  • 基于 Promise

  • 支持浏览器和 node.js

  • 可添加拦截器和转换请求和响应数据

  • 请求可以取消

  • 自动转换 JSON 数据

  • 客户端支持防范 XSRF

本文 将 带大家一起阅读 axios 的源码, 按照执行流程解析当中的一些封装技巧,分析功能实现。

Axios整体代码结构分析

├── /dist/                     # 项目输出目录
├── /lib/                      # 项目源码目录
│ ├── /cancel/                 # 定义取消功能
│ ├── /core/                   # 一些核心功能
│ │ ├── Axios.js               # axios的核心主类
│ │ ├── dispatchRequest.js     # 用来调用http请求适配器方法发送请求
│ │ ├── InterceptorManager.js  # 拦截器构造函数
│ │ └── settle.js              # 根据http响应状态,改变Promise的状态
│ ├── /helpers/                # 一些辅助方法
│ ├── /adapters/               # 定义请求的适配器 xhr、http
│ │ ├── http.js                # 实现http适配器
│ │ └── xhr.js                 # 实现xhr适配器
│ ├── axios.js                 # 对外暴露接口
│ ├── defaults.js              # 默认配置
│ └── utils.js                 # 公用工具
├── package.json               # 项目信息
├── index.d.ts                 # 配置TypeScript的声明文件
└── index.js                   # 入口文件

Axios执行流程整体分析

Axios执行文件分析

  • 入口 /lib/axios.js

function createInstance(defaultConfig) {
    var context = new Axios(defaultConfig);
    // 自定义bind方法,等同于var instance = Axios.prototype.request.bind(context)
    // 这句的作用是将request方法指向instance,上下文是context,可以使用instance(option)
    // 调用  var instance = bind(Axios.prototype.request, context);

    // 根据前面extend方法,使Axios.prototype的方法扩展到instance对象上,这样instance就有了get,post,put等方法
    // 并且制定上细纹是context, 这样axios中方法, this执行context
    // utils.extend(instance, Axios.prototype, context);
    // 将context自身属性和方法扩展到instance上, 因为extend内部使用的forEach方法对对象做for in 遍历时, 只遍历对象本身的属性, 而不会遍历原型链上的属性
    // 这样,instance 就有了  defaults、interceptors 属性。(这两个属性后面我们会介绍)
    // Copy context to instance
    utils.extend(instance, context);

    return instance;
}
// 接收默认配置项作为参数(后面会介绍配置项),创建一个Axios实例,最终会被作为对象导出
var axios = createInstance(defaults);

/lib/core/Axios.js是核心包,axios各种方式('delete', 'get', 'head', 'options','post', 'put', 'patch')都是通过request方法发出的。每个axios实例都有一个interceptors实例属性,interceptors对象上有两个属性request、response。InterceptorManager用来实现拦截器的,这个构造函数原型上有3个方法:use、eject、forEach。我们首先看下 InterceptorManager的实现:

  • 拦截器包 /lib/core/InterceptorManager.js

function InterceptorManager() {
    this.handlers = []; // 存放拦截器方法,数组内每一项都是有两个属性的对象,两个属性分别对应成功和失败后执行的函数。
}

// 往拦截器里添加拦截方法,使用 unshift,会导致use 后添加的先执行,先添加的后执行,use就是我们在http.js中书写的拦截器
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
    this.handlers.push({
        fulfilled: fulfilled,
        rejected: rejected
    });
    return this.handlers.length - 1;
};

// 用来注销指定的拦截器
InterceptorManager.prototype.eject = function eject(id) {
    if (this.handlers[id]) {
        this.handlers[id] = null;
    }
};

// 遍历this.handlers,并将this.handlers里的每一项作为参数传给fn执行
InterceptorManager.prototype.forEach = function forEach(fn) {
    utils.forEach(this.handlers, function forEachHandler(h) {
        if (h !== null) {
            fn(h);
        }
    });
};
  • 核心包  /lib/core/Axios.js

Axios.js主要处理了两个部分,复用请求方法、实现拦截器。 当我们使用 Axios 的实例去发送请求,使用的方法get、post等都是复用了request方法,在request方法中通过 arguments 获取传入的参数,实现了传入参数的重载。 拦截器是axios的一大特色,它的实现原理其实不复杂,核心就是promise的链式调用。

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

    config = mergeConfig(this.defaults, config);
    config.method = config.method ? config.method.toLowerCase() : 'get';

    // Hook up interceptors middleware
    // chain 是一个数组
    var chain = [dispatchRequest, undefined];
    var promise = Promise.resolve(config);
    // 使用 use 添加 fulfilled 与 rejected 添加到队列中
    // 添加 request 拦截函数的时候使用的是unshift, 这样会导致 use 后添加的先执行,先添加的后执行
    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
        chain.unshift(interceptor.fulfilled, interceptor.rejected);
    });
    // response使用的是push,添加拦截相应函数,这里是先添加先执行,后添加后执行。
    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
        chain.push(interceptor.fulfilled, interceptor.rejected);
    });
    // chain  [fulfilled, rejected, ... dispatchRequest, undefined ....,fulfilled, rejected]
    // 这里补充一下 fulfilled, rejected 都是肯定是成对出现的, 具体原因可看 InterceptorManager
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值