
axios AxiosHeaders 请求头方法全集从 set/get 到 normalize 的源码级实践指南【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios本篇基于 axios 官方文档《Métodos de encabezados》header-methods.md展开系统讲解AxiosHeaders类的全部核心方法——构造、set、get、has、delete、clear、normalize、concat、toJSON、toString、静态from以及内建快捷访问器。读完后你将掌握如何以比直接操作普通对象更安全、更可控的方式管理 HTTP 请求头以及每个方法在 lib/core/AxiosHeaders.js 中的底层实现逻辑与典型调用链。为什么需要 AxiosHeaders先看懂构造器自引入AxiosHeaders类以来axios 提供了一组专门用于操作请求头的方法。相比直接摆弄一个普通对象AxiosHeaders在键名大小写归一、重复键合并、头部值清洗等方面做了统一处理是更便捷的设置、获取与删除请求头方式的载体。类定义在 lib/core/AxiosHeaders.js构造器签名如下constructor(headers?: RawAxiosHeaders | AxiosHeaders | string);它接受一个可选参数用于初始化实例可以是任意数量的头对象键名大小写不敏感也可以是一段以换行符分隔的原始头部文本。源码中构造器只做了一件事——把参数交给setconstructor(headers) { headers this.set(headers); }这解释了为什么构造函数、set单键值、set对象、set原始字符串三种用法的行为完全一致。传入原始字符串时set内部会走 parseHeaders.js 的解析逻辑按行切分、冒号左侧为键并转小写、右侧为值例如const headers new AxiosHeaders( Host: www.bing.com User-Agent: curl/7.54.0 Accept: */*); console.log(headers); // Object [AxiosHeaders] { // host: www.bing.com, // user-agent: curl/7.54.0, // accept: */* // }值得注意的是parseHeaders内置了一张ignoreDuplicateOf列表lib/helpers/parseHeaders.js#L7-L25涵盖host、content-type、user-agent等 Node.js HTTP 模块会忽略重复项的头部——解析原始文本时这些键只保留第一个值而set-cookie会被收集为数组其余重复键以, 拼接。这一行为是从原始报文解析场景出发的刻意设计。set三种输入形态与 rewrite 覆盖语义set是写入请求头的主入口支持三种调用形态以及一个控制覆盖行为的可选参数rewriteset(headerName, value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher); set(headerName, value, rewrite?: (this: AxiosHeaders, value: string, name: string) boolean); set(headers?: RawAxiosHeaders | AxiosHeaders | string, rewrite?: boolean); set(headers?: Iterable[string, AxiosHeaderValue], rewrite?: boolean);参数rewrite控制覆盖行为语义如下rewrite 取值行为false若该头已有值非undefined则不覆盖undefined默认会覆盖除非现有值被显式设置为falsetrue无条件覆盖也可以传入用户自定义函数由它决定是否覆盖——函数接收当前值、头名称以及头对象本身。另外空名称或纯空格名称会被直接忽略。源码中的判定逻辑非常直观lib/core/AxiosHeaders.js#L206-L222function setHeader(_value, _header, _rewrite) { const lHeader normalizeHeader(_header); // trim toLowerCase if (!lHeader) { return; // 空名或纯空格 - 忽略 } const key utils.findKey(self, lHeader); // 查找已存在的同名键保留原大小写 if ( !key || self[key] undefined || _rewrite true || (_rewrite undefined self[key] ! false) ) { self[key || _header] normalizeValue(_value); } }这里有两个关键细节大小写不敏感的键查找normalizeHeader对名称做trim().toLowerCase()而实际写入时用utils.findKey找到实例上已存在的原始键名因此Content-Type与content-type指向同一个键。false是占位语义把某头显式设为false后默认写入不再覆盖它只有rewrite true才能改回——单元测试 tests/unit/axiosHeaders.test.js#L48-L77 专门验证了这两条规则。接受 Map 等可迭代键值对set的第三个形态接受可迭代的键值对序列如Mapconst headers new AxiosHeaders(); headers.set( new Map([ [X-Trace-Id, abc123], [Accept, application/json], ]) );从源码结构看可迭代分支会先把迭代结果归拢到一个 null-proto 对象迭代项不是二元数组时会抛出TypeError(Object iterator must return a key-value pair)lib/core/AxiosHeaders.js#L232-L251。测试中还有针对性验证即便Object.prototype被注入同名键或污染了Symbol.iterator也不会把原型链上的值混入迭代来源tests/unit/axiosHeaders.test.js#L87-L129。保留特定头部的大小写AxiosHeaders保留第一个匹配键的大小写形式。你可以利用这一点先用undefined预设一个键名之后再写入值从而固定某个头部的大小写。这一技巧在对接对头部大小写行为不规范的服务器时很有用完整的defaults与axios.create用法见 保留特定请求头大小写。写入值的阶段还会经过normalizeValue与 sanitizeHeaderValue字符串值会被剥离 C0 控制字符与 DEL0x00–0x08、0x0A–0x1F、0x7F并去掉两端空格/水平制表符数组值递归处理false与null原样保留。get匹配器与解析器含 parseParametersget用于读取头部值可传入头名称、可选的 matcher 或 parsermatcher 的默认值为trueparser 可以是用于从头部值中提取内容的正则get(headerName: string, parser: typeof AxiosHeaders.parseParameters): AxiosHeaderParameters; get(headerName: string, parser: RegExp): RegExpExecArray | null; get(headerName: string, matcher?: true | AxiosHeaderParser): AxiosHeaderValue;官方示例展示了四种典型用法const headers new AxiosHeaders({ Content-Type: multipart/form-data; boundaryAsrf456BGe4h, }); console.log(headers.get(Content-Type)); // multipart/form-data; boundaryAsrf456BGe4h console.log(headers.get(Content-Type, true)); // 用 \s,; 分隔符把字符串解析为键值对 // [Object: null prototype] { // multipart/form-data: undefined, // boundary: Asrf456BGe4h // } const quotedHeaders new AxiosHeaders({ Content-Type: multipart/form-data; boundarya,b, }); console.log({ ...quotedHeaders.get(Content-Type, AxiosHeaders.parseParameters), }); // { boundary: a,b } console.log( headers.get(Content-Type, (value, name, headers) { return String(value).replace(/a/g, ZZZ); }) ); // multipZZZrt/form-dZZZtZZZ; boundZZZryAsrf456BGe4h console.log(headers.get(Content-Type, /boundary(\w)/)?.[0]); // boundaryAsrf456BGe4h对照源码lib/core/AxiosHeaders.js#L259-L287可以看到分派顺序header先经normalizeHeader归一再用utils.findKey找到实际键名——所以取值不区分大小写无 parser 直接返回值parser true走parseTokens用正则/([^\s,;])\s*(?:\s*([^,;]))?/g做轻量分词注意它对带引号的内容不做处理函数 parser 以该实例为this调用正则 parser 执行exec其它类型直接抛TypeError(parser must be boolean|regexp|function)。parseParameters更严格的 HTTP 参数解析器AxiosHeaders.parseParameters是可选的解析器针对 HTTP 归一化参数值返回 null-proto 对象参数名一律转小写剥离带引号字符串两端的引号解码转义的\与\\并保留引号内的逗号/分号对不带引号的值只去掉 RFC 定义的可选空白空格与水平制表符。其实现是一个手写的字符级状态机lib/core/AxiosHeaders.js#L92-L149按切换引号状态、按0x5c记录转义、在引号外遇到,或;时切出参数片段参数名需匹配parameterNameRE/^[!#$%*\-.^_|~0-9A-Za-z]$/才会被收录。一个安全细节值得注意解析器会跳过__proto__、constructor、prototype这三个危险键名避免通过构造恶意头部值向解析结果注入原型污染面lib/core/AxiosHeaders.js#L115-L121。而传true时仍走上面提到的parseTokens旧分词器以保持向后兼容。has存在性判断has(header: string, matcher?: AxiosHeaderMatcher): boolean;当且仅当头已定义值不是undefined时返回true。源码中的判定lib/core/AxiosHeaders.js#L289-L303是key this[key] ! undefined (!matcher || matchHeaderValue(...))——所以把某头显式设为false后has依然返回true只有undefined才视为不存在。可选的 matcher 可进一步按值过滤。delete 与 clear删除与清空delete(header: string | string[], matcher?: AxiosHeaderMatcher): boolean;delete支持单个头名称或名称数组可按值匹配器筛选至少删除一个头时返回true。clear(matcher?: AxiosHeaderMatcher): boolean;clear无参时清空全部头部传入 matcher 时只删除匹配项——且此时 matcher 是拿头名称而非值做比较。这一点在源码里体现得很明确clear调用matchHeaderValue时传入了第五个参数isHeaderNameFilter true使字符串/正则过滤器作用在键名上lib/core/AxiosHeaders.js#L332-L346。匹配器支持三种形式字符串子串包含、正则test、函数统一由 lib/core/AxiosHeaders.js#L153-L171 的matchHeaderValue处理。normalize合并重复键适配器与拦截器的收尾动作如果你直接以属性方式修改过头部对象如headers.Foo 2可能出现同名但大小写不同的多个键。normalize会把重复键合并为一个。axios 在每次拦截器执行后内部都会调用它。format传true时把头名转为小写并首字母大写cOntEnt-typeContent-Type传false则保持原格式const headers new AxiosHeaders({ foo: 1, }); headers.Foo 2; headers.FOO 3; console.log(headers.toJSON()); // [Object: null prototype] { foo: 1, Foo: 2, FOO: 3 } console.log(headers.normalize().toJSON()); // [Object: null prototype] { foo: 3 } console.log(headers.normalize(true).toJSON()); // [Object: null prototype] { Foo: 3 }返回this以便链式调用。实现上lib/core/AxiosHeaders.js#L348-L373它遍历自身对已出现过的归一化名称直接合并到已有键上否则按format决定是否做formatHeadertrim().toLowerCase()后按单词首字母大写重命名。拦截器后调用这一点可以在仓库里直接找到证据XHR、HTTP、fetch 三个适配器以及transformData都会先取头再normalizelib/adapters/xhr.js#L21const requestHeaders AxiosHeaders.from(_config.headers).normalize();lib/adapters/http.js#L766const headers AxiosHeaders.from(config.headers).normalize();lib/adapters/fetch.js#L456发送前执行headers.normalize()再转 ByteString 头部对象lib/core/transformData.js#L22-L25transformRequest回调执行前后各normalize()一次也就是说normalize是 axios 请求管线里保证头部键唯一性的守门员而不是可选项。concat组合头部并固定大小写预设concat把当前实例与若干目标组合成新的AxiosHeaders实例目标是字符串时按原始 HTTP 头格式解析目标是AxiosHeaders实例时直接合并。这在需要预置大小写 后填值的组合场景特别有用const headers AxiosHeaders.concat( { content-type: undefined }, { Content-Type: application/octet-stream } );concat(...targets: ArrayAxiosHeaders | RawAxiosHeaders | string | undefined | null): AxiosHeaders;静态实现非常简洁new this(first)后对每个目标依次setlib/core/AxiosHeaders.js#L418-L424因此目标中已有的键默认不会覆盖前者——配合undefined预设即可固定content-type的小写形式。toJSON 与 toString序列化的两种形态toJSON把内部所有头值解析为一个 null-proto 新对象跳过null与false的值asStrings传true时把数组值用逗号连接为字符串toJSON(asStrings: true): Recordstring, string; toJSON(asStrings?: false): Recordstring, string | string[];toString则返回不带 CRLF 的原始 HTTP 头文本块每行一个name: value对lib/core/AxiosHeaders.js#L395-L399底层同样基于toJSONtoString(): string;另外从源码可以看到实例实现了[Symbol.iterator]迭代toJSON()的 entries和[Symbol.toStringTag] AxiosHeaders可以直接for...of遍历或用instanceof识别类型。静态 from幂等的类型归一from(thing?: AxiosHeaders | RawAxiosHeaders | string): AxiosHeaders;若传入的已经是AxiosHeaders实例则原样返回否则用其构造新实例。源码就一行return thing instanceof this ? thing : new this(thing);lib/core/AxiosHeaders.js#L410-L412。前面提到的三个适配器正是靠AxiosHeaders.from(config.headers).normalize()把配置里可能是普通对象、字符串或AxiosHeaders的头部统一归一。快捷访问器setContentType 一族类上预置了以下快捷方法每个头部各有 get/set/has 三个setContentType、getContentType、hasContentTypesetContentLength、getContentLength、hasContentLengthsetAccept、getAccept、hasAcceptsetUserAgent、getUserAgent、hasUserAgentsetContentEncoding、getContentEncoding、hasContentEncoding它们由AxiosHeaders.accessor静态方法批量生成以Content-Type、Content-Length、Accept、Accept-Encoding、User-Agent、Authorization六个头部为名单调用accessorlib/core/AxiosHeaders.js#L452-L459内部通过buildAccessors在原型上用toCamelCase生成如getContentEncoding这样的方法转调this.get/set/has.call(this, header, ...)lib/core/AxiosHeaders.js#L182-L196。两个源码层面的工程细节访问器属性描述符刻意设为 null-proto__proto__: null防止被污染的Object.prototype.get在写入途中把数据描述符变成访问器描述符——这是对原型污染攻击面的防御性写法accessor是公开的静态方法你也可以为任意自定义头如X-Trace-Id动态生成访问器tests/unit/axiosHeaders.test.js#L599-L628 中有headers.constructor.accessor(foo)的验证用例。此外源码里还有一个文档未展开的细节reduceDescriptors把set/get/...等原型方法做了保留名热修lib/core/AxiosHeaders.js#L461-L470避免把名为set、get的头部当作属性赋值时覆盖掉同名方法。小结方法选择速查场景推荐方法关键依据初始化 / 批量写入构造器、set对象、字符串、Maplib/core/AxiosHeaders.js#L198-L257条件覆盖set(name, value, rewrite)默认不覆盖false占位值提取参数如 boundaryget(name, AxiosHeaders.parseParameters)处理引号、转义与原型污染防护存在性判断hasfalse也算已定义精准删除delete/clear(matcher)clear的 matcher 作用于键名消除重复键normalize(format?)适配器与 transformData 管线自动调用组合 大小写预设AxiosHeaders.concat、from固定头部大小写序列化toJSON(asStrings?)/toStringnull-proto、跳过false常用头简写getContentType等访问器accessor可扩展自定义头AxiosHeaders的设计思路可以概括为对外提供大小写不敏感、值自动清洗、重复键可归一的统一头容器对内通过normalize保证适配器拿到的总是干净的头部集合。理解了set的 rewrite 语义、parseParameters的引号状态机和normalize在请求管线中的自动触发你就能在拦截器、实例默认值和请求级配置三处安全地操控请求头。相关文档headers 总览大小写保留与拦截器设置、api-reference、单元测试 tests/unit/axiosHeaders.test.js。【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考