Axios源码笔记 | 深入解析 Core 核心处理引擎,从源码透视HTTP客户端设计哲学
【摘要】 一、Core 核心架构全景1.1 核心模块关系Axios核心引擎采用分层架构设计,各模块职责明确:控制中枢:Axios.js负责整体流程控制拦截系统:InterceptorManager实现请求/响应拦截请求调度:dispatchRequest处理实际请求派发错误处理:AxiosError统一错误格式数据处理:transformData处理数据转换配置管理:mergeConfig实现多级配置...
一、Core 核心架构全景
1.1 核心模块关系
Axios核心引擎采用分层架构设计,各模块职责明确:
- 控制中枢:Axios.js负责整体流程控制
- 拦截系统:InterceptorManager实现请求/响应拦截
- 请求调度:dispatchRequest处理实际请求派发
- 错误处理:AxiosError统一错误格式
- 数据处理:transformData处理数据转换
- 配置管理:mergeConfig实现多级配置合并
二、核心模块深度解析
2.1 Axios.js:控制中枢
2.1.1 核心类架构
class Axios {
constructor(instanceConfig) {
this.defaults = instanceConfig; // 全局默认配置
this.interceptors = { // 拦截器管理系统
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
}
- 配置管理中心:维护
defaults
作为全局默认配置。 - 拦截器容器:通过InterceptorManager管理请求/响应拦截器。
2.1.2 请求处理中枢
async request(configOrUrl, config) {
try {
return await this._request(...);
} catch (err) {
// 增强错误堆栈追踪
}
}
_request() {
// 处理参数重载(支持axios(url, config)语法)
// 配置合并(mergeConfig)
// 处理headers(使用AxiosHeaders)
// 构建拦截器链
}
- 多参数处理:支持
axios(url, config)
和axios(config)
两种调用方式 - 错误处理增强:自动补充错误堆栈信息
2.1.3 拦截器执行机制
// 请求拦截器链
requestInterceptorChain.unshift(...)
// 响应拦截器链
responseInterceptorChain.push(...)
// 异步执行流程
const chain = [dispatchRequest, undefined];
chain.unshift(...requestInterceptorChain);
chain.push(...responseInterceptorChain);
- 请求拦截器:FILO(先进后出)顺序执行
- 响应拦截器:FIFO(先进先出)顺序执行
- 同步/异步模式:根据拦截器配置自动选择执行方式
2.1.4 HTTP方法适配器
// 无数据方法(GET等)
utils.forEach(['delete', 'get', 'head', 'options'], ...)
// 含数据方法(POST等)
utils.forEach(['post', 'put', 'patch'], function() {
// 生成标准方法和Form表单方法
function generateHTTPMethod(isForm) {...}
})
- 自动生成方法:通过遍历生成所有HTTP方法
- 表单处理:特殊处理
xxxForm
方法(自动设置Content-Type)
2.1.5 核心辅助功能
getUri(config) {
// 构建完整URL
buildFullPath(...);
// 参数序列化
buildURL(...);
}
- URL构建:自动合并baseURL与请求URL
- 参数序列化:支持自定义序列化函数
2.1.6 关键设计特点
- 配置分层管理:支持全局配置+请求级配置的深度合并。
- 异步流程控制:通过Promise链实现拦截器流水线。
- 扩展性设计:拦截器机制支持灵活的功能扩展。
- 语法兼容:同时支持现代async/await和传统Promise用法。
该文件作为Axios的核心控制器,协调了配置管理、请求派发、拦截器流水线、方法适配等关键流程,体现了中间件架构的设计思想。
2.2 InterceptorManager.js:拦截器系统
2.2.1 数据结构设计
class InterceptorManager {
constructor() {
this.handlers = []; // 拦截器存储容器
}
}
- 环形队列结构:使用数组存储拦截器对象。
- 空位标记:被移除的拦截器置为 null(非物理删除)。
2.2.2 注册拦截器 (use)
use(fulfilled, rejected, options) {
this.handlers.push({
fulfilled, // 成功回调
rejected, // 失败回调
synchronous: options?.synchronous, // 同步模式标识
runWhen: options?.runWhen // 执行条件判断
});
return this.handlers.length - 1; // 返回索引作为ID
}
- 支持链式配置:返回拦截器ID用于后续管理。
- 条件执行:通过 runWhen 实现动态拦截控制。
2.2.3 移除拦截器 (eject)
eject(id) {
if (this.handlers[id]) {
this.handlers[id] = null; // 标记删除而非物理删除
}
}
- 逻辑删除机制:保持数组索引稳定性。
- 内存优化:避免频繁数组操作影响性能。
2.2.4 遍历机制 (forEach)
forEach(fn) {
utils.forEach(this.handlers, h => {
if (h !== null) fn(h); // 自动跳过已移除的拦截器
});
}
- 安全遍历:自动过滤 null 值项。
- 执行效率:O(n) 时间复杂度遍历。
2.2.5 拦截器对象结构
{
fulfilled: (config) => {}, // 成功处理函数
rejected: (error) => {}, // 错误处理函数
synchronous: false, // 是否同步执行
runWhen: (config) => true // 执行条件判断函数
}
2.2.6 执行流程控制
当与 Axios 核心配合时:
- 请求拦截器:逆序执行(后添加的先执行)。
- 响应拦截器:正序执行(先添加的先执行)。
- 条件执行:通过 runWhen 判断是否执行拦截器。
// Axios.js 中的处理逻辑示例
this.interceptors.request.forEach(interceptor => {
if (interceptor.runWhen(config) === false) return;
// 加入执行链...
});
2.2.7 关键设计特点
- 松耦合设计:拦截器与核心逻辑解耦。
- 灵活控制:支持同步/异步两种执行模式。
- 动态管理:运行时增删改查拦截器。
- 条件过滤:通过 runWhen 实现智能拦截。
2.3 dispatchRequest.js:请求调度中心
2.3.1 预处理阶段
export default function dispatchRequest(config) {
throwIfCancellationRequested(config); // 前置取消检查
config.headers = AxiosHeaders.from(config.headers); // 头部标准化
// 请求数据转换
config.data = transformData.call(config, config.transformRequest);
// 自动设置 Content-Type
if (['post', 'put', 'patch'].includes(config.method)) {
config.headers.setContentType('application/x-www-form-urlencoded', false);
}
}
- 取消安全检查:在请求发起前进行双重取消检查(CancelToken 和 AbortSignal)。
- 头部标准化:将 headers 转换为 AxiosHeaders 实例。
- 智能 Content-Type:为常见数据提交方法设置默认类型(不覆盖用户自定义值)。
2.3.2 适配器调度
const adapter = adapters.getAdapter(config.adapter || defaults.adapter);
return adapter(config).then(...)
- 环境自适应:自动选择 XHR(浏览器)或 HTTP(Node.js)适配器。
- 扩展支持:允许自定义适配器实现特殊网络协议。
2.3.3 数据转换流水线
// 请求数据转换
transformData.call(config, config.transformRequest)
// 响应数据转换
response.data = transformData.call(config, config.transformResponse, response)
- 双向转换:支持请求/响应数据的自定义转换管道。
- 默认处理:包含 JSON 解析、URL 编码等基础转换逻辑
2.3.4 异常处理机制
function onAdapterRejection(reason) {
if (!isCancel(reason)) {
// 处理非取消类错误
if (reason.response) {
reason.response.data = transformData(...)
}
}
return Promise.reject(reason);
}
- 错误分类:区分取消错误与真实网络错误。
- 错误数据转换:对非常规响应(如 4xx/5xx)进行数据转换。
2.3.5 关键设计特点
1、取消感知设计:
function throwIfCancellationRequested(config) {
if (config.cancelToken) { /* Check CancelToken */ }
if (config.signal?.aborted) { /* Check AbortSignal */ }
}
- 同时支持新旧两种取消方案。
- 在请求发起前和响应接收后进行双重检查。
2、数据转换管道:
// 典型转换流程示例
请求数据 -> transformRequest 数组 -> 网络适配器
响应数据 -> transformResponse 数组 -> 用户接收
3、适配器抽象层:
// 适配器注册机制示例
adapters.register('custom', (config) => {
// 自定义网络实现
})
2.3.6 核心价值体现
- 统一入口:聚合所有预处理逻辑。
- 异常隔离:确保转换错误不会导致进程崩溃。
- 扩展基点:通过适配器机制支持多种网络协议。
- 性能优化:避免不必要的转换操作。
该模块作为 Axios 网络通信的最后一道关口,在确保安全性的同时,为上层提供了统一的网络抽象接口。
三、关键支持模块解析
3.1 AxiosError.js:错误处理系统
3.1.1 错误类继承体系
class AxiosError extends Error {
constructor(message, code, config, request, response) {
super(message);
// 保留完整错误堆栈
Error.captureStackTrace(this, this.constructor);
// 扩展属性
this.config = config;
this.request = request;
this.response = response;
this.code = code; // 标准化错误码
}
}
- Error 继承:完整保留原生错误特性。
- 上下文保留:携带请求配置、请求实例、响应对象。
- 状态码双保险:
code
与status
并存(兼容不同错误来源)。
3.1.2 标准化错误码
Object.defineProperties(AxiosError, {
ECONNABORTED: {value: 'ECONNABORTED'}, // 连接中止
ETIMEDOUT: {value: 'ETIMEDOUT'}, // 超时错误
ERR_CANCELED: {value: 'ERR_CANCELED'}, // 手动取消
// ...其他 10+ 标准错误码
});
- 跨环境统一:浏览器/Node.js 共用同一套错误标识。
- 错误分类:包含网络错误、配置错误、响应错误等类型。
3.1.3 错误特征标识
Object.defineProperty(AxiosError.prototype, 'isAxiosError', {
value: true // 快速识别标志
});
- 类型检测:替代
instanceof
检查,避免多实例问题。 - 兼容性增强:应对不同打包环境下的类继承问题。
3.1.4 错误序列化
toJSON() {
return {
message: this.message,
config: utils.toJSONObject(this.config), // 安全序列化
code: this.code,
status: this.status
};
}
- 安全转换:过滤循环引用等危险结构。
- 关键信息保留:包含调试所需的最小数据集。
3.1.5 错误包装机制
static from(error, code, config, request, response) {
const axiosError = Object.create(this.prototype);
// 保留原始错误信息
axiosError.cause = error; // Error Cause 标准提案实现
return axiosError;
}
- 错误链支持:通过
cause
属性保留原始错误。 - 无缝转换:将第三方库错误转换为 Axios 标准格式。
3.1.6 设计亮点
1、上下文完整性:
try {/* 请求 */}
catch (err) {
console.log(err.config.url); // 可追溯出错请求
console.log(err.response.status); // 查看服务端响应
}
2、错误码标准化:
if (err.code === AxiosError.ECONNABORTED) {
// 处理连接中止
}
3、安全序列化:
// 日志记录时自动过滤敏感信息
JSON.stringify(err)
4、错误溯源:
console.log(err.cause); // 查看底层系统错误
该错误系统通过标准化、结构化、可追溯的设计,显著提升了异步请求的调试效率和错误处理能力。
3.2 mergeConfig.js:配置合并策略
3.2.1 合并策略矩阵
const mergeMap = {
url: valueFromConfig2, // 完全使用新配置
method: valueFromConfig2,
data: valueFromConfig2,
baseURL: defaultToConfig2, // 新配置优先
headers: 深度合并策略, // 特殊对象合并
validateStatus: mergeDirectKeys // 条件合并
// ...其他 30+ 配置项策略
};
3.2.2 核心合并策略类型
1、新配置优先 (valueFromConfig2)
function valueFromConfig2(_, b) {
return b !== undefined ? clone(b) : undefined;
}
- 适用场景:URL、请求方法等需完全覆盖的配置。
- 典型配置项:
url
method
data
2、默认值优先 (defaultToConfig2)
function defaultToConfig2(a, b) {
return b !== undefined ? clone(b) : clone(a);
}
- 适用场景:基础配置需要继承默认值。
- 典型配置项:
baseURL
timeout
withCredentials
3、深度合并 (mergeDeepProperties)
function mergeDeepProperties(a, b) {
if (均为对象) return 深度合并;
if (b是数组) return 复制新数组;
return b ?? a;
}
- 适用场景:复杂对象结构配置。
- 典型配置项:
headers
(特殊处理)transformRequest
transformResponse
4、条件合并 (mergeDirectKeys)
function mergeDirectKeys(a, b) {
return config2存在该属性 ? 合并值 : 保留config1值;
}
- 适用场景:需要条件判断的配置。
- 典型配置项:
validateStatus
3.2.3 Headers 特殊处理
headers: (a, b) => mergeDeepProperties(
headersToObject(a),
headersToObject(b),
true // 启用大小写不敏感合并
)
- 转换机制:将 AxiosHeaders 实例转为普通对象。
- 合并特点:
- 保留双方特有 headers。
- 同名 header 新配置覆盖旧值。
- 自动处理大小写(如
Content-Type
与content-type
)。
3.2.5 关键设计原则
1、不变性原则
function clone(source) {
if (数组) return source.slice();
if (对象) return {...source};
return source;
}
- 始终保持原始配置不可变。
2、安全递归合并:
utils.merge 实现:
- 跳过原型链属性
- 处理循环引用
- 控制合并深度(默认 10 层)
3、策略扩展性:
// 自定义合并策略示例
mergeMap.customProp = (a, b) => {
return a + b; // 自定义合并逻辑
}
四、高级特性实现
4.1 transformData.js:数据转换引擎
该模块是 Axios 数据转换的核心处理器,负责请求/响应数据的多阶段转换流程。
4.1.1 转换流程架构
export default function transformData(fns, response) {
const config = this || defaults; // 获取当前配置
const context = response || config; // 确定执行上下文
const headers = AxiosHeaders.from(context.headers); // 标准化请求头
let data = context.data; // 原始数据
// 执行转换流水线
utils.forEach(fns, function(fn) {
data = fn(data, headers.normalize(), response?.status);
});
return data;
}
4.1.2 转换函数执行特点
1、链式传递:
// 示例转换函数队列
const transformRequest = [
data => JSON.stringify(data), // 序列化
data => encryptPayload(data) // 加密
];
// 执行顺序:序列化 -> 加密
2、上下文绑定:
fn.call(config, data, headers, status)
this
指向当前请求配置。- 可访问完整的配置参数。
3、头信息交互:
headers.normalize() // 标准化头信息键名(如 content-type -> Content-Type)
- 每次转换前更新头信息状态。
- 允许转换函数修改头信息(如根据数据类型设置 Content-Type)。
4.1.3 双模式工作机制
1、请求阶段转换:
// 请求处理流程
config.transformRequest.forEach(fn => {
data = fn(data, headers);
});
- 典型处理:
- JSON 序列化。
- URL 参数编码。
- FormData 转换。
2、响应阶段转换:
// 响应处理流程
config.transformResponse.forEach(fn => {
data = fn(data, headers, status);
});
- 典型处理:
- JSON 解析。
- 数据解密。
- 错误格式标准化。
4.1.4 转换函数签名规范
type TransformFunction = (
data: any,
headers: AxiosHeaders,
status?: number
) => any;
- 输入:原始数据 + 头信息 + HTTP 状态码(仅响应阶段)。
- 输出:处理后的新数据。
4.1.5 关键设计特点
1、不可变处理:
let data = context.data; // 保留原始数据引用
data = fn(data); // 每次转换创建新数据
- 确保原始数据不被意外修改。
2、状态感知转换:
// 根据 HTTP 状态码进行不同处理
function statusAwareTransform(data, headers, status) {
if (status >= 400) {
return { error: data };
}
return data;
}
3、头信息联动:
function setContentType(data, headers) {
if (typeof data === 'string') {
headers.set('Content-Type', 'text/plain');
}
return data;
}
4.2 settle.js:响应状态处理
4.2.1 验证条件判断
const validateStatus = response.config.validateStatus;
if (!response.status || !validateStatus || validateStatus(response.status)) {
resolve(response);
}
三层短路逻辑:
- 无状态码时直接成功(异常情况)。
- 没有配置验证函数时默认成功。
- 有验证函数时以函数结果为准。
4.2.2 错误处理机制
reject(new AxiosError(
'Request failed with status code ' + response.status,
[/*...*/][Math.floor(response.status/100)-4], // 错误类型选择器
response.config,
response.request,
response
));
- 错误类型动态判断:
4xx
状态码 ➔ERR_BAD_REQUEST
(客户端错误)。5xx
状态码 ➔ERR_BAD_RESPONSE
(服务端错误)
- 错误对象包含:配置信息、请求实例、响应对象,便于调试。
4.2.3 设计特点
- 灵活的状态验证:允许通过
validateStatus
配置自定义状态码验证逻辑。 - 错误分类明确:通过状态码百位数自动区分错误类型。
- 完整上下文保留:错误对象携带完整的请求/响应上下文信息。
五、结语
通过对 Core 核心引擎的深度剖析,我们揭示了其分层架构、拦截器链、数据管道三大设计支柱。从网页的配置合并到网页的拦截器机制,每个模块都体现了高内聚低耦合的设计哲学。
收获:
- 拦截器系统采用Promise链实现中间件模式。
- 配置管理系统通过原型链继承实现灵活覆盖。
- 适配器模式完美解决跨环境兼容问题。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)