十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Axios 请求头深度指南:AxiosHeaders 类的用法、合并语义与源码实现剖析

Axios 请求头深度指南:AxiosHeaders 类的用法、合并语义与源码实现剖析 Axios 请求头深度指南AxiosHeaders 类的用法、合并语义与源码实现剖析【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios本篇围绕 axios 官方文档《请求头》展开讲解AxiosHeaders类的类 Map API、四种内部值类型string/null/false/undefined的合并与序列化语义以及在实际请求、拦截器、响应读取中的正确操作方式。读完本文你将掌握在配置与拦截器中设置请求头、保留特定键名大小写、移除 axios 默认请求头的完整方案并能从源码层面理解键名不区分大小写、值净化防注入等底层机制的实现位置。1. AxiosHeaders键名不区分大小写的类 Map 请求头容器axios 暴露了自定义的AxiosHeaders类通过类 Map 的 API 来操作请求头并保证键名不区分大小写。axios 内部使用该类管理请求头同时也将其暴露给用户以提供便利。尽管 HTTP 请求头本身不区分大小写axios 仍会保留原始请求头的大小写形式以满足风格需求并在服务器错误地将请求头大小写视为有效区分时提供兼容。直接操作请求头对象的旧方式request.headers[X-Foo] bar仍然可用但已废弃不建议在新代码中使用。从源码结构看这些承诺由 lib/core/AxiosHeaders.js 中的实现兑现// lib/core/AxiosHeaders.js节选 function normalizeHeader(header) { return header String(header).trim().toLowerCase(); }不区分大小写的查找set、get、has、delete都先经过normalizeHeader归一化再通过utils.findKey在对象中做大小写无关的键匹配。该函数遍历自身键名并逐个toLowerCase()比对返回真实键名实现见 lib/utils.js保留首个匹配键的大小写set写入时使用self[key || _header] ...见 lib/core/AxiosHeaders.js 的setHeader内部函数——若已存在等价键则沿用已有键名即第一个写入时的拼写否则使用新传入的键名。这正是保留第一个匹配键的大小写形式的来源类 Map 的完整方法集set/get/has/delete/clear/concat/toJSON/toString并实现了Symbol.iterator与Symbol.toStringTag返回AxiosHeaders见 lib/core/AxiosHeaders.js。此外类上还通过AxiosHeaders.accessor静态方法为常用头注册了快捷方法包括Content-Type、Content-Length、Accept、Accept-Encoding、User-Agent、Authorization即setContentType/getContentType/hasContentType等三件套见 lib/core/AxiosHeaders.js。2. 四种内部值类型控制设置与合并逻辑AxiosHeaders实例可以包含不同类型的内部值用于控制设置和合并逻辑。axios 在将最终请求头对象发送前会调用toJSON方法。请求头值可以是以下类型之一值行为string正常的字符串值将被发送到服务器null转换为 JSON 时跳过该请求头false转换为 JSON 时跳过该请求头并额外表示调用set方法时必须将rewrite选项设置为true才能覆盖此值axios 内部使用此机制允许用户选择不发送某些请求头如User-Agent或Content-Typeundefined值未设置注意如果请求头值不是undefined则视为已设置。false的占位锁语义是 axios 请求头系统中最容易忽视、也最关键的设计。它在源码中有两处配合// lib/core/AxiosHeaders.jstoJSONL379-L389 toJSON(asStrings) { const obj Object.create(null); utils.forEach(this, (value, header) { value ! null value ! false (obj[header] asStrings utils.isArray(value) ? value.join(, ) : value); }); return obj; }toJSON显式过滤null与false因此这两类值最终都不会进入发出的请求。而在set内部lib/core/AxiosHeaders.js覆盖判定为if ( !key || self[key] undefined || _rewrite true || (_rewrite undefined self[key] ! false) ) { self[key || _header] normalizeValue(_value); }翻译过来即只有当键不存在、当前值为undefined、显式传入rewrite true、或默认模式下当前值不是false时写入才会生效。也就是说一个被设为false的头部普通set无法覆盖它。这个机制在 axios 默认行为中被广泛使用以 lib/core/dispatchRequest.js 为例对post/put/patch请求执行config.headers.setContentType(application/x-www-form-urlencoded, false)——第二个参数rewrite false表示仅在用户尚未显式设置Content-Type时才补默认值同理 lib/defaults/index.js 中的transformRequest也会以setContentType(application/json, false)的方式补 JSON 类型。用户一旦在配置里显式指定了Content-Type默认值就不会抢占。3. 初始化时机与可迭代性请求头对象始终在拦截器和转换器中被初始化为AxiosHeaders实例。其入口在 lib/core/dispatchRequest.jsconfig.headers AxiosHeaders.from(utils.getSafeProp(config, headers));AxiosHeaders.from(thing)会在thing已是实例时直接返回否则包装成新实例。响应侧同理成功与失败路径都会执行response.headers AxiosHeaders.from(response.headers)见 lib/core/dispatchRequest.js 与 lib/core/dispatchRequest.js。因此在请求拦截器中拿到的request.headers必然是AxiosHeaders可以放心调用其方法。文档中的示例axios.interceptors.request.use((request: InternalAxiosRequestConfig) { request.headers.set(My-header, value); request.headers.set({ My-set-header1: my-set-value1, My-set-header2: my-set-value2, }); // 禁止 axios 后续设置此请求头 request.headers.set(User-Agent, false); request.headers.setContentType(text/plain); // 直接访问的方式已废弃 request.headers[My-set-header2] newValue; return request; });AxiosHeaders对象也是可迭代的可以在循环中使用或转换为数组或对象。迭代器直接构建在toJSON()之上lib/core/AxiosHeaders.js[Symbol.iterator]() { return Object.entries(this.toJSON())[Symbol.iterator](); }这意味着遍历天然遵循toJSON的过滤规则null/false的头部不会出现在迭代结果中且数组值会被展开。因此for-of循环、forEach、展开运算符、Object.fromEntries等一切可迭代用法均可直接使用const headers new AxiosHeaders({ foo: 1, bar: 2, baz: 3, }); for (const [header, value] of headers) { console.log(header, value); } // foo 1 // bar 2 // baz 34. 在请求中设置请求头最常见的设置请求头的方式是在请求配置或实例配置的headers选项中设置。该选项接受普通对象、AxiosHeaders实例、以换行符分隔的原始头部字符串甚至Map等可迭代键值对见第 5 节与 lib/core/AxiosHeaders.js 中set的多形态处理// 针对单个请求 await axios.get(/api/data, { headers: { Accept-Language: en-US, X-Request-ID: abc123, }, }); // 针对实例应用于每个请求 const api axios.create({ headers: { X-App-Version: 2.0.0, }, });5. 保留特定请求头的大小写axios 请求头名称不区分大小写但AxiosHeaders会保留第一个匹配键的大小写形式即第一个写入该头时的拼写被固化后续set会沿用既有键名。如果你需要为大小写敏感的非标准服务器保留特定大小写可以在defaults中先以undefined值预设键名之后再按常规方式设置值——预设时set会把undefined值连同键名一起写入undefined在toJSON时视为未设置不影响最终发送随后真正赋值时就沿用了这个键名的拼写const api axios.create(); api.defaults.headers.common { content-type: undefined, accept: undefined, }; await api.put(url, data, { headers: { Content-Type: application/octet-stream, Accept: application/json, }, });也可以在组合请求头时直接使用AxiosHeaders.concat实现import axios, { AxiosHeaders } from axios; const headers AxiosHeaders.concat( { content-type: undefined }, { Content-Type: application/octet-stream } ); await axios.put(url, data, { headers });从源码看lib/core/AxiosHeaders.js 中的静态concat实现为以第一个参数构造新实例再依次对每个目标执行set因此第一个目标{ content-type: undefined }先占住了小写键名第二个目标的大小写不同的键在findKey匹配到既有键后不再改写拼写组合结果即保留content-type的小写形式。6. 在拦截器中设置动态请求头拦截器是附加动态请求头如认证令牌的合适位置因为令牌可能在实例首次创建时还不可用api.interceptors.request.use((config) { const token getAuthToken(); // 在请求时读取 config.headers.set(Authorization, Bearer ${token}); return config; });由于请求拦截器执行时config.headers已经完成AxiosHeaders初始化第 3 节所述AxiosHeaders.from调用发生在dispatchRequest边界而拦截器链在其前后运行这里可以直接使用set方法若希望令牌过期被刷新后能覆盖旧值而绕过false锁也可传入rewrite参数或匹配函数完整参数签名参见请求头方法文档。7. 读取响应头响应头以AxiosHeaders实例的形式在response.headers上可用所有头名称均为小写——这一行为来自响应头的原始解析器 lib/helpers/parseHeaders.js它在把key: value行解析为对象时统一执行key.trim().toLowerCase()并对set-cookie特殊处理为数组以支持一次响应携带多条 Cookieconst response await axios.get(/api/data); console.log(response.headers[content-type]); // application/json; charsetutf-8 console.log(response.headers.get(x-request-id)); // abc123对可能多次出现的set-cookieAxiosHeaders还提供了专门的 getSetCookie() 方法值已是数组则原样返回是单值则包一层null/false则返回空数组保证调用方总能拿到数组语义。8. 移除 axios 默认请求头如需取消 axios 默认设置的请求头如Content-Type或User-Agent将其值设置为false即第 2 节讲解的占位锁机制在用户侧的应用await axios.post(/api/data, payload, { headers: { Content-Type: false, // 让浏览器自动设置例如针对 FormData }, });典型场景是提交FormData时浏览器需要自行生成带boundary的multipart/form-data类型将Content-Type置false后lib/core/dispatchRequest.js 与 lib/defaults/index.js 中以rewrite false的默认赋值都因false锁而无法覆盖toJSON又将其过滤掉最终请求头中不携带Content-Type交由浏览器/运行环境补全。单元测试 tests/unit/axiosHeaders.test.js 精确验证了这一覆盖规则headers.set(foo, false); headers.set(foo, value2); // 不生效值仍为 false assert.strictEqual(headers.get(foo), false); headers.set(foo, value2, true); // rewritetrue 才覆盖 assert.strictEqual(headers.get(foo), value2);9. 源码级安全细节值净化、原型污染与注入防护axios 的请求头实现在多个边界做了防御性处理理解这些细节有助于判断哪些输入是安全可透传的1) 头值净化防请求头注入。所有字符串值写入前都经过sanitizeHeaderValuelib/core/AxiosHeaders.js 的normalizeValue调用 lib/helpers/sanitizeHeaderValue.js剥离 C0 控制字符含\r、\n与 DEL防止攻击者通过恶意值注入额外请求头// tests/unit/axiosHeaders.test.jsL204-L210 headers.set(x-test, \t safe\r\nInjected: true \u0000); assert.strictEqual(headers.get(x-test), safeInjected: true);同时非控制类的 Unicode 字符如中文、日文会被完整保留仅控制字符被清除见 tests/unit/axiosHeaders.test.js数组型头部如set-cookie同样逐项净化。2) 键名合法性校验。通过单字符串路径设置时键名须匹配isValidHeaderName正则lib/core/AxiosHeaders.js空字符串或纯空白键名会被静默跳过而不抛错tests/unit/axiosHeaders.test.js。3) 原型污染防护。解析头参数时__proto__、constructor、prototype三个危险键名会被显式丢弃lib/core/AxiosHeaders.js消费可迭代来源时只认对象自身的Symbol.iterator继承自被污染Object.prototype的迭代器不会被使用为快捷方法生成属性描述符时使用__proto__: null的描述符避免被污染的原型属性干扰lib/core/AxiosHeaders.js。这些防护均有对应回归测试覆盖见 tests/unit/axiosHeaders.test.js。4) 参数解析器。除get(header, true)的旧版分词器外axios 还提供规范化解析器AxiosHeaders.parseParameters它支持带引号参数值保留引号内逗号/分号、解码转义的引号与反斜杠并返回null原型映射lib/core/AxiosHeaders.js用法示例const headers new AxiosHeaders({ Content-Type: multipart/form-data; boundarya,b, }); console.log({ ...headers.get(Content-Type, AxiosHeaders.parseParameters) }); // { boundary: a,b }10. 小结与延伸阅读AxiosHeaders通过键名不区分大小写 首个键名拼写固化 四值语义 toJSON序列化过滤四个机制统一了 axios 在拦截器、转换器、默认值合并与适配器之间的请求头处理。掌握其核心在于设置用set必要时配合rewrite读取用get遍历直接for-of需要抑制默认头时置false需要覆盖false锁时必须rewrite true需要固定键名大小写时先用undefined占位再赋值或用AxiosHeaders.concat组合。完整的方法 APIset的rewrite参数形态、get的解析器、has/delete/clear/normalize/from/toString及全部快捷方法签名请参阅文档站 请求头方法 页面实现细节可进一步查阅 lib/core/AxiosHeaders.js 与测试文件 tests/unit/axiosHeaders.test.js、浏览器端行为测试 tests/browser/headers.browser.test.js。【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表