adapters.js
adapters.js 是 Axios 实现跨平台请求的核心,位于 lib/adapters/adapters.js,负责管理和解析不同平台的适配器(http、xhr、fetch)。
适配器允许你自定义 axios 处理请求数据的方式。默认情况下,axios 使用 ['xhr', 'http', 'fetch'] 的有序优先级列表,并选择当前环境支持的第一个适配器。实际上,这意味着在浏览器中使用 xhr ,在 Node.js 中使用 http ,在两者均不可用的环境(如 Cloudflare Workers 或 Deno)中使用 fetch 。 fetch 适配器是 1.7.0 版本中引入的新适配器。
1 2 3 4 5 6 7 8 9 /lib/adapters/http.js const isHttpAdapterSupported = typeof process !== 'undefined' && utils.kindOf (process) === 'process' ;export default isHttpAdapterSupported && function httpAdapter (config ) { ... }
1 2 3 4 5 6 7 8 /lib/adapters/xhr.js const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined' ;export default isXHRAdapterSupported && function (config ) { ... }
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 import utils from '../utils.js' ;import httpAdapter from './http.js' ;import xhrAdapter from './xhr.js' ;import * as fetchAdapter from './fetch.js' ;import AxiosError from '../core/AxiosError.js' ;const knownAdapters = { http : httpAdapter, xhr : xhrAdapter, fetch : { get : fetchAdapter.getFetch , }, }; utils.forEach (knownAdapters, (fn, value ) => { if (fn) { try { Object .defineProperty (fn, 'name' , { __proto__ : null , value }); } catch (e) { } Object .defineProperty (fn, 'adapterName' , { __proto__ : null , value }); } });const renderReason = (reason ) => `- ${reason} ` ;const isResolvedHandle = (adapter ) => utils.isFunction (adapter) || adapter === null || adapter === false ;function getAdapter (adapters, config ) { 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 && (utils.isFunction (adapter) || (adapter = adapter.get (config)))) { 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; }export default { getAdapter, adapters : knownAdapters, };
内置适配器
在项目我们一般不会配置 adapter 参数,而是使用默认的配置适配器。
1 2 3 4 5 6 7 8 9 10 11 12 const defaults = { ... adapter: ['xhr' , 'http' , 'fetch' ], ... }function createInstance (defaultConfig) { const context = new Axios(defaultConfig); }const axios = createInstance(defaults);
可以通过 adapter 配置选项按名称选择内置适配器:
1 2 3 4 5 6 7 8 9 10 11 const instance = axios.create ({ adapter : "fetch" });const instance = axios.create ({ adapter : "xhr" });const instance = axios.create ({ adapter : "http" });const instance = axios.create ({ adapter : ["fetch" , "xhr" , "http" ] });
自定义适配器
要创建自定义适配器,需要编写一个接受 config 对象并返回 Promise 的函数,该 Promise 需解析为有效的 axios 响应对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import axios from "axios" ;import { settle } from "axios/unsafe/core/settle.js" ;function myAdapter (config ) { return new Promise ((resolve, reject ) => { fetch (config.url , { method : config.method ?.toUpperCase () ?? "GET" , }) .then (async (fetchResponse) => { const responseData = await fetchResponse.text (); const response = { data : responseData, status : fetchResponse.status , statusText : fetchResponse.statusText , headers : Object .fromEntries (fetchResponse.headers .entries ()), config, request : null , }; settle (resolve, reject, response); }) .catch (reject); }); }const instance = axios.create ({ adapter : myAdapter });