
axios 配置默认值完全解析全局 defaults、实例级隔离与合并优先级机制【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios本文基于 axios 官方文档的 “Config defaults” 章节法语版 docs/fr/pages/advanced/config-defaults.md英文版见 docs/pages/advanced/config-defaults.md系统讲解 axios 三层配置默认值体系axios.defaults全局默认值、axios.create()实例默认值、请求级配置覆盖并结合当前仓库源码lib/defaults/index.js、lib/core/mergeConfig.js、lib/core/Axios.js验证其合并优先级、data不参与继承等关键行为帮助你建立可复制、可运行的默认值配置方案并规避跨域凭据泄漏等安全陷阱。全局默认配置axios.defaultsaxios 允许你指定作用于所有请求的配置默认值。baseURL、headers、timeout等属性都可以被设置为全局默认值官方文档给出的示例如下axios.defaults.baseURL https://jsonplaceholder.typicode.com/posts; axios.defaults.headers.common[Authorization] AUTH_TOKEN; axios.defaults.headers.post[Content-Type] application/x-www-form-urlencoded;这段代码的语义是此后所有使用默认实例发出的请求相对路径都会拼接到baseURL之后headers.common[Authorization]会附加到每一个请求所有 HTTP 方法headers.post[Content-Type]只影响 POST 请求方法级 header 会在发送前与common合并见下文“请求发出时的 header 扁平化”一节。安全警告全局 header 会发给每一个主机官方文档在此处给出了一个明确的 warning原文以告警框形式强调全局 header 会被发送到每一个 hotehost。如果你的应用与多个域名通信设置axios.defaults.headers.common[Authorization]会把 token 发送到所有这些域名包括你可能并不控制的第三方 API。对于任何携带凭据的客户端应改用具有限定baseURL的自定义实例。这不是理论风险而是默认实例的固有行为默认实例没有主机边界common头对一切目标主机生效。因此最佳实践是——凭据只挂在 baseURL 被严格限定的实例上而不是全局axios.defaults上。源码视角默认实例是如何诞生的在 lib/axios.js 中模块级的默认实例就是由库级默认值对象构造出来的function createInstance(defaultConfig) { const context new Axios(defaultConfig); // ... // 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本身就是createInstance(defaults)的产物defaults来自 lib/defaults/index.js你写axios.defaults.timeout 5000时修改的正是这个实例的defaults属性后续每次请求都会经过mergeConfig(this.defaults, config)与之合并见 lib/core/Axios.jsinstance.create(instanceConfig)工厂方法会先mergeConfig(defaultConfig, instanceConfig)再新建实例所以新实例会继承当前实例的默认值这是多层实例体系能够逐层叠加的基础。库级默认值对象的完整内容节选自 lib/defaults/index.jsconst defaults { transitional: transitionalDefaults, adapter: [xhr, http, fetch], transformRequest: [ ... ], // 默认请求体转换器JSON / URLSearchParams / multipart 处理 transformResponse: [ ... ], // 默认响应 JSON 解析器 timeout: 0, // 0 表示不创建超时 xsrfCookieName: XSRF-TOKEN, xsrfHeaderName: X-XSRF-TOKEN, maxContentLength: -1, maxBodyLength: -1, env: { FormData: ..., Blob: ... }, validateStatus: function (status) { return status 200 status 300; }, headers: { common: { Accept: application/json, text/plain, */*, Content-Type: undefined, }, }, }; // 为每个方法建立独立的空 header 桶 utils.forEach([delete, get, head, post, put, patch, query], (method) { defaults.headers[method] {}; });几个值得注意的点timeout: 0是库级默认值源码注释明确写着 “If set to 0 (default) a timeout is not created”这也是文档优先级示例的起点headers的结构是{ common, delete, get, head, post, put, patch, query }的“桶”结构common预置了Accept每个方法桶初始为空对象完整请求配置项说明可参考官方 Request configuration 文档header 的读写 API 见 Headers 文档。自定义实例默认值axios.create()axios 实例在创建时就被声明了属于自己的默认值这些默认值既可以通过axios.create()的入参声明也可以在创建后通过实例的defaults属性覆盖。官方示例var instance axios.create({ baseURL: https://jsonplaceholder.typicode.com/posts, timeout: 1000, headers: { Authorization: foobar }, }); instance.defaults.headers.common[Authorization] AUTH_TOKEN;要点axios.create(config)的入参成为该实例的defaults。从 lib/core/Axios.js 可以看到构造器只是简单存储this.defaults instanceConfig || {}因此传入什么就用什么未传入的项会回落到合并链上的下一层见下文的优先级创建后仍可通过instance.defaults.xxx ...直接改写如上例中对instance.defaults.headers.common[Authorization]的赋值由于instance.create会先把父实例默认值合并进来lib/axios.js你还可以从已有实例继续派生子实例形成“全局 → 实例 A → 实例 A 的子实例”的多层默认值体系。这个模式与前文安全警告直接对应把带凭据的客户端做成 baseURL 受限的独立实例token 就只会被发往该实例配置的域名而不会像挂在axios.defaults上那样扩散到全部请求。配置优先级Config order of precedence配置的合并遵循一个明确的优先级顺序官方文档的表述是首先设置库的默认值然后是实例的默认属性最后是请求的配置参数。即覆盖力度从弱到强为库默认值lib/defaults 实例默认值instance.defaults / create 入参 请求级 config官方文档用一个timeout的三段式例子演示这个顺序第一步创建一个只带库默认值的实例。此时 timeout 的取值是库默认值0不超时const instance axios.create();第二步把实例级 timeout 默认值覆盖为2500毫秒。此后所有经由该实例发出的请求都将在 2.5 秒后超时instance.defaults.timeout 2500;第三步发起一次 timeout 为5000毫秒的请求。这次请求会等待 5 秒才超时——请求级配置压过了实例默认值instance.get(/longRequest, { timeout: 5000, });源码验证优先级是如何实现的每一次请求发出前lib/core/Axios.js 都会执行config mergeConfig(this.defaults, config);mergeConfig(config1, config2)中config1是默认值实例级或库级、config2是请求配置因此“后者覆盖前者”天然成立。但具体每一项用哪种覆盖策略由 lib/core/mergeConfig.js 中的mergeMap决定这是优先级规则里最容易被误解的部分const mergeMap { url: valueFromConfig2, // 只取请求级 method: valueFromConfig2, // 只取请求级 data: valueFromConfig2, // 只取请求级关键 baseURL: defaultToConfig2, // 请求级优先缺省回落到默认值 transformRequest: defaultToConfig2, transformResponse: defaultToConfig2, timeout: defaultToConfig2, // 文档示例的 timeout 走此策略 adapter: defaultToConfig2, responseType: defaultToConfig2, withCredentials: defaultToConfig2, // ... 其余项省略完整列表见 lib/core/mergeConfig.js validateStatus: mergeDirectKeys, // 任一侧显式声明即取该侧 headers: (a, b, prop) mergeDeepProperties(headersToObject(a), headersToObject(b), prop, true), // 深度合并大小写不敏感 };三种策略的行为差异策略行为典型字段对文档示例的影响defaultToConfig2请求级有值取请求级否则回落到默认值baseURL、timeout、adapter、responseTypetimeout0 → 2500 → 5000的覆盖链正是此策略valueFromConfig2只取请求级默认值中的该字段被直接忽略url、method、data默认值里写data是不生效的mergeDeepProperties两侧普通对象做深度合并后者键覆盖前者键headers实例默认 header 与请求 header 按键合并而非整体替换mergeDirectKeys哪一侧显式拥有该键就取哪一侧validateStatus避免undefined误覆盖单元测试 tests/unit/core/mergeConfig.test.js 也直接验证了 timeout 的回落行为mergeConfig(defaults, { timeout: 123 })得到merged.timeout 123。特殊项data 不参与默认值继承文档在优先级一节特别强调了一个反直觉但非常重要的规则有些选项是请求专属的只会从请求配置中读取。data就是其中之一axios不会从全局默认值或实例默认值继承请求体也不对它做深度合并。如果每个请求都需要附带共用的 body 字段请使用请求拦截器或transformRequest来添加并注意限定作用范围避免把敏感值发送到错误的端点。源码层面这一行为由mergeMap中data: valueFromConfig2一行实现lib/core/mergeConfig.js并有专门的回归测试佐证tests/unit/core/mergeConfig.test.jsit(does not inherit request options, () { const localDefaults { method: __sample method__, data: { foo: true }, }; const merged mergeConfig(localDefaults, {}); expect(merged.method).toBeUndefined(); expect(merged.data).toBeUndefined(); });即把data写进实例默认值合并结果中它会是undefined。这条规则的设计意图是防止默认值里残留的请求体被“顺带”发出去。实践建议与文档一致需要为每类请求附加公共 body 字段时写一个请求拦截器见 Interceptors 文档或自定义transformRequest其默认实现见 lib/defaults/index.js在该逻辑中严格限定适用条件如仅匹配特定 baseURL/路径避免敏感字段被注入到不该接收它的端点。同理url和method也只取请求级——这解释了为什么通过axios.create()无法预置“默认请求路径”。请求发出时的 header 扁平化headers的桶结构common 方法名最终会在请求阶段被压平为实际发往适配器的请求头。这一步发生在 lib/core/Axios.js// Set config.method config.method ( utils.getSafeProp(config, method) || utils.getSafeProp(this.defaults, method) || get ).toLowerCase(); // Flatten headers let contextHeaders headers utils.merge(headers.common, headers[config.method]); headers utils.forEach( [delete, get, head, post, put, patch, query, common], (method) { delete headers[method]; } ); config.headers AxiosHeaders.concat(contextHeaders, headers);规则可以概括为方法解析请求级method→ 实例默认method→get统一转小写common头与该方法桶的头先合并方法桶覆盖common同名键得到contextHeaderscommon与各方法桶键被删除剩余的平铺键与方法合并结果一起构成最终 header 集合这正是文档示例中headers.common[Authorization]生效于所有方法、而headers.post[Content-Type]只影响 POST 请求的底层原因也与mergeConfig中 headers 走大小写不敏感深度合并的行为一致。小结三层默认值库默认值lib/defaults/index.js→ 实例默认值axios.create()入参或instance.defaults→ 请求级配置后者逐级覆盖前者timeout的0 → 2500 → 5000是官方给出的标准演示合并不是简单覆盖mergeMap按字段区分策略baseURL/timeout可回落默认值defaultToConfig2url/method/data只认请求级valueFromConfig2headers深度合并且大小写不敏感安全边界不要把Authorization等凭据放进axios.defaults.headers.common——它会发往默认实例访问的每一个主机应改用 baseURL 受限的独立实例承载凭据公共请求体不要试图通过默认值注入data在合并时被显式排除正确做法是请求拦截器或transformRequest。【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考