axios源码分析之请求adapter

ops/2024/11/1 15:18:23/

axios源码分析之请求adapter

axios changeLog

注:axios从 v1.7.0-beta.0 支持了fetch

v1.7.0-beta.0 changgeLog

Featuresadapter: add fetch adapter; (#6371) (a3ff99b)Contributors to this releaseavatar Dmitriy Mozgovoyavatar Jay

v1.7.0-beta.0 之前的版本

以 v0.27.2版本为例 是如何使用 Adapter

当处理请求时会使用 dispatchRequest方法,该方法出现了adapter方法,adapter方法中传入了config(即构造axios请求时传入的请求配置,包含headers,请求参数等),

  • 当成功时会返回 response
  • 当失败时会返回 Promise.reject(reason)

【注】axios\lib\core\dispatchRequest.js

  /// ....codevar defaults = require('../defaults');///...code var adapter = config.adapter || defaults.adapter;return adapter(config).then(function onAdapterResolution(response) {throwIfCancellationRequested(config);// Transform response dataresponse.data = transformData.call(config,response.data,response.headers,config.transformResponse);return response;}, function onAdapterRejection(reason) {if (!isCancel(reason)) {throwIfCancellationRequested(config);// Transform response dataif (reason && reason.response) {reason.response.data = transformData.call(config,reason.response.data,reason.response.headers,config.transformResponse);}}return Promise.reject(reason);});

来看看defaults.adapter 到底是什么黑魔法?

【注】一般我们在构造axios 请求时不会自己传入adapter,所以此处不会去关注 config.adapter

var adapter = config.adapter || defaults.adapter;

从dispatchRequest.js 源码中我们可以看到 defaults 来源于 axios\lib\defaults\index.js 文件, 该文件导出了defaults对象,defaults.adapter 来源于getDefaultAdapter 返回的值,

getDefaultAdapter 方法

  • 先判断 XMLHttpRequest 是否存在,存在就使用 xhr 请求
  • 判断process 是否为 undefined 判断是否为node 环境,然后就用 http 包发起起请求
function getDefaultAdapter() {var adapter;if (typeof XMLHttpRequest !== 'undefined') {// For browsers use XHR adapteradapter = require('../adapters/xhr');} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {// For node use HTTP adapteradapter = require('../adapters/http');}return adapter;
}

【注】axios\lib\defaults\index.js

'use strict';var utils = require('../utils');
var normalizeHeaderName = require('../helpers/normalizeHeaderName');
var AxiosError = require('../core/AxiosError');
var transitionalDefaults = require('./transitional');
var toFormData = require('../helpers/toFormData');var DEFAULT_CONTENT_TYPE = {'Content-Type': 'application/x-www-form-urlencoded'
};function setContentTypeIfUnset(headers, value) {if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) {headers['Content-Type'] = value;}
}function getDefaultAdapter() {var adapter;if (typeof XMLHttpRequest !== 'undefined') {// For browsers use XHR adapteradapter = require('../adapters/xhr');} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {// For node use HTTP adapteradapter = require('../adapters/http');}return adapter;
}function stringifySafely(rawValue, parser, encoder) {if (utils.isString(rawValue)) {try {(parser || JSON.parse)(rawValue);return utils.trim(rawValue);} catch (e) {if (e.name !== 'SyntaxError') {throw e;}}}return (encoder || JSON.stringify)(rawValue);
}var defaults = {transitional: transitionalDefaults,adapter: getDefaultAdapter(),transformRequest: [function transformRequest(data, headers) {normalizeHeaderName(headers, 'Accept');normalizeHeaderName(headers, 'Content-Type');if (utils.isFormData(data) ||utils.isArrayBuffer(data) ||utils.isBuffer(data) ||utils.isStream(data) ||utils.isFile(data) ||utils.isBlob(data)) {return data;}if (utils.isArrayBufferView(data)) {return data.buffer;}if (utils.isURLSearchParams(data)) {setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');return data.toString();}var isObjectPayload = utils.isObject(data);var contentType = headers && headers['Content-Type'];var isFileList;if ((isFileList = utils.isFileList(data)) || (isObjectPayload && contentType === 'multipart/form-data')) {var _FormData = this.env && this.env.FormData;return toFormData(isFileList ? {'files[]': data} : data, _FormData && new _FormData());} else if (isObjectPayload || contentType === 'application/json') {setContentTypeIfUnset(headers, 'application/json');return stringifySafely(data);}return data;}],transformResponse: [function transformResponse(data) {var transitional = this.transitional || defaults.transitional;var silentJSONParsing = transitional && transitional.silentJSONParsing;var forcedJSONParsing = transitional && transitional.forcedJSONParsing;var strictJSONParsing = !silentJSONParsing && this.responseType === 'json';if (strictJSONParsing || (forcedJSONParsing && utils.isString(data) && data.length)) {try {return JSON.parse(data);} catch (e) {if (strictJSONParsing) {if (e.name === 'SyntaxError') {throw AxiosError.from(e, AxiosError.ERR_BAD_RESPONSE, this, null, this.response);}throw e;}}}return data;}],/*** A timeout in milliseconds to abort a request. If set to 0 (default) a* timeout is not created.*/timeout: 0,xsrfCookieName: 'XSRF-TOKEN',xsrfHeaderName: 'X-XSRF-TOKEN',maxContentLength: -1,maxBodyLength: -1,env: {FormData: require('./env/FormData')},validateStatus: function validateStatus(status) {return status >= 200 && status < 300;},headers: {common: {'Accept': 'application/json, text/plain, */*'}}
};utils.forEach(['delete', 'get', 'head'], function forEachMethodNoData(method) {defaults.headers[method] = {};
});utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
});module.exports = defaults;

v1.7.0-beta.0 之后版本

主要增加fetch 请求方式

adapters文件夹下增加 axios\lib\adapters\adapters.js 文件
重写了 getAdapter 方法

【注】axios\lib\adapters\adapters.js

import utils from '../utils.js';
import httpAdapter from './http.js';
import xhrAdapter from './xhr.js';
import fetchAdapter from './fetch.js';
import AxiosError from "../core/AxiosError.js";const knownAdapters = {http: httpAdapter,xhr: xhrAdapter,fetch: fetchAdapter
}utils.forEach(knownAdapters, (fn, value) => {if (fn) {try {Object.defineProperty(fn, 'name', {value});} catch (e) {// eslint-disable-next-line no-empty}Object.defineProperty(fn, 'adapterName', {value});}
});const renderReason = (reason) => `- ${reason}`;const isResolvedHandle = (adapter) => utils.isFunction(adapter) || adapter === null || adapter === false;export default {getAdapter: (adapters) => {adapters = utils.isArray(adapters) ? adapters : [adapters];const {length} = adapters;let nameOrAdapter;let adapter;const rejectedReasons = {};for (let i = 0; i < length; i++) {nameOrAdapter = adapters[i];let id;adapter = nameOrAdapter;if (!isResolvedHandle(nameOrAdapter)) {adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()];if (adapter === undefined) {throw new AxiosError(`Unknown adapter '${id}'`);}}if (adapter) {break;}rejectedReasons[id || '#' + i] = adapter;}if (!adapter) {const reasons = Object.entries(rejectedReasons).map(([id, state]) => `adapter ${id} ` +(state === false ? 'is not supported by the environment' : 'is not available in the build'));let s = length ?(reasons.length > 1 ? 'since :\n' + reasons.map(renderReason).join('\n') : ' ' + renderReason(reasons[0])) :'as no adapter specified';throw new AxiosError(`There is no suitable adapter to dispatch the request ` + s,'ERR_NOT_SUPPORT');}return adapter;},adapters: knownAdapters
}

http://www.ppmy.cn/ops/130166.html

相关文章

内网穿透技术选型PPTP(点对点隧道协议)和 FRP(Fast Reverse Proxy)

PPTP&#xff08;点对点隧道协议&#xff09;和 FRP&#xff08;Fast Reverse Proxy&#xff09;是两种实现内网穿透的技术&#xff0c;但它们的工作原理、使用场景和特点有很大区别。以下是它们的详细比较&#xff1a; PPTP&#xff08;Point-to-Point Tunneling Protocol&am…

C++接口集成、身份实名认证-游戏防沉迷,保障未成年人健康

随着互联网的快速发展&#xff0c;网络游戏在年轻人中越来越受欢迎。然而&#xff0c;未成年玩家长时间沉迷游戏的问题却引发了社会的广泛关注。为了应对这一现象&#xff0c;各大网络游戏平台纷纷引入翔云身份证实名认证接口&#xff0c;以有效辨别用户身份&#xff0c;建立完…

Xamarin 存档报错 XABLD7000 Xamarin.Tools.Zip.ZipException

Xamarin App 调试正常&#xff0c;存档时发生错误&#xff1b; XABLD7000: Xamarin.Tools.Zip.ZipException: Renaming temporary file failed: Permission denied 查了资料&#xff0c;说是要去掉 快速部署&#xff1b;如下图&#xff1a; 当我去掉勾选时&#xff0c;还是依然…

聚簇索引和非聚簇索引B+树的关系

在数据库系统中&#xff0c;聚簇索引和非聚簇索引通常都基于 B 树 实现&#xff08;例如 MySQL 的 InnoDB 引擎&#xff09;。尽管它们的数据存储方式有所不同&#xff0c;但其底层结构和 B 树 的特性相辅相成&#xff0c;适合于高效的查询操作。以下是聚簇索引、非聚簇索引和 …

Spring整合Mybatis过程

配置文件 springConfig --> [jdbcConfig mybatisConfig] jdbc配置文件进行基本的数据库连接池配置 mybatis配置文件进行SqlSessionFactory Bean 和 MapperScannerConfigurer Bean的创建 在Spring容器启动时&#xff0c;系统会根据配置创建并初始化所有MyBatis所需的Bean…

SVN Update出错问题解决三大步

1.下载sqlite3.exe 放到 .svn 目录下&#xff0c;启动命令行&#xff0c;敲入命令&#xff1a; sqlite3.exe wc.db 2.这时&#xff0c;进到了sqlite的命令行环境&#xff0c;可以操作该数据库了&#xff0c;首先我们输入命令&#xff1a; .tables 3. 将该数据库中的表都…

探讨Java深搜算法的学习笔记

大家好&#xff0c;我是 V 哥。深度优先搜索&#xff08;DFS&#xff09;是一种图遍历算法&#xff0c;它优先深入到某条路径的尽头&#xff0c;再回溯到前一个节点继续探索其他路径&#xff0c;直到找到目标或遍历完整个图。DFS的应用场景广泛&#xff0c;可以用于路径搜索、连…

降本60% ,阿里云 EMR StarRocks 全新发布存算分离版本

简介&#xff1a; 阿里云 EMR Serverless StarRocks 现已推出全新存算分离版本&#xff0c;该版本不仅基于开源 StarRocks 进行了全面优化&#xff0c;实现了存储与计算解耦架构&#xff0c;还在性能、弹性伸缩以及多计算组隔离能力方面取得了显著进展。通过实现存储与计算资源…