diff --git a/README.md b/README.md index a8d2a1b8..83e44394 100644 --- a/README.md +++ b/README.md @@ -1580,6 +1580,38 @@ for (const [header, value] of headers) { // baz 3 ``` +### Preserving a specific header case + +Header names are case-insensitive, but `AxiosHeaders` keeps the case of the first matching key it sees. +If you need a specific case for non-standard case-sensitive servers, define a case preset with `undefined` and then set the value later: + +```js +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', + }, +}); +``` + +You can also compose the same behavior with `AxiosHeaders.concat`: + +```js +const headers = axios.AxiosHeaders.concat( + { 'content-type': undefined }, + { 'Content-Type': 'application/octet-stream' } +); + +await axios.put(url, data, { headers }); +``` + ### new AxiosHeaders(headers?) Constructs a new `AxiosHeaders` instance. diff --git a/docs/pages/advanced/header-methods.md b/docs/pages/advanced/header-methods.md index 65fbb5b3..173f65a2 100644 --- a/docs/pages/advanced/header-methods.md +++ b/docs/pages/advanced/header-methods.md @@ -45,6 +45,8 @@ The rewrite argument controls the overwriting behaviour: The option can also accept a user-defined function that determines whether the value should be overwritten or not. The function receives the current value, header name, and the headers object as arguments. +`AxiosHeaders` keeps the case of the first matching key it sees. You can use this to preserve specific header casing by seeding a key with `undefined` and then setting values later. See [Preserving a specific header case](/pages/advanced/headers#preserving-a-specific-header-case). + ## Get The `get` method is used to retrieve the value of a header. The method can be called with a single header name, an optional matcher, or a parser. The matcher is defaulted to `true`. The parser can be a regular expression that is used to extract the value from the header. @@ -58,26 +60,26 @@ An example of some of the possible usages of the `get` method is shown below: ```js const headers = new AxiosHeaders({ - "Content-Type": "multipart/form-data; boundary=Asrf456BGe4h", + 'Content-Type': 'multipart/form-data; boundary=Asrf456BGe4h', }); -console.log(headers.get("Content-Type")); +console.log(headers.get('Content-Type')); // multipart/form-data; boundary=Asrf456BGe4h -console.log(headers.get("Content-Type", true)); // parse key-value pairs from a string separated with \s,;= delimiters: +console.log(headers.get('Content-Type', true)); // parse key-value pairs from a string separated with \s,;= delimiters: // [Object: null prototype] { // 'multipart/form-data': undefined, // boundary: 'Asrf456BGe4h' // } console.log( - headers.get("Content-Type", (value, name, headers) => { - return String(value).replace(/a/g, "ZZZ"); + headers.get('Content-Type', (value, name, headers) => { + return String(value).replace(/a/g, 'ZZZ'); }) ); // multipZZZrt/form-dZZZtZZZ; boundZZZry=Asrf456BGe4h -console.log(headers.get("Content-Type", /boundary=(\w+)/)?.[0]); +console.log(headers.get('Content-Type', /boundary=(\w+)/)?.[0]); // boundary=Asrf456BGe4h ``` @@ -123,11 +125,11 @@ If the headers object was changed directly, it can cause duplicates with the sam ```js const headers = new AxiosHeaders({ - foo: "1", + foo: '1', }); -headers.Foo = "2"; -headers.FOO = "3"; +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' } @@ -142,6 +144,15 @@ Returns `this` for chaining. Merges the instance with targets into a new AxiosHeaders instance. If the target is a string, it will be parsed as RAW HTTP headers. If the target is an AxiosHeaders instance, it will be merged with the current instance. +This is useful for case presets when composing headers. For example: + +```js +const headers = AxiosHeaders.concat( + { 'content-type': undefined }, + { 'Content-Type': 'application/octet-stream' } +); +``` + ```js concat(...targets: Array): AxiosHeaders; ``` diff --git a/docs/pages/advanced/headers.md b/docs/pages/advanced/headers.md index 200ae115..9dc12f43 100644 --- a/docs/pages/advanced/headers.md +++ b/docs/pages/advanced/headers.md @@ -79,6 +79,39 @@ const api = axios.create({ }); ``` +## Preserving a specific header case + +Axios header names are case-insensitive, but `AxiosHeaders` keeps the case of the first matching key it sees. If you need a specific case for a server with non-standard case-sensitive behavior, define a case preset in defaults and then set values as usual. + +```js +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', + }, +}); +``` + +You can also do this with `AxiosHeaders` directly when composing headers: + +```js +import axios, { AxiosHeaders } from 'axios'; + +const headers = AxiosHeaders.concat( + { 'content-type': undefined }, + { 'Content-Type': 'application/octet-stream' } +); + +await axios.put(url, data, { headers }); +``` + ## Setting headers in an interceptor Interceptors are the right place to attach dynamic headers like auth tokens, because the token may not be available when the instance is first created: