Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

req.header vs req.headers in Express

I am using Express with Body Parser. Given a below header key:

X-Master-Key

When I am using the below code snippet, it fails to output the value

req.headers['X-Master-Key'] // Fails

but when the above is changed to, it works

req.headers['x-master-key'] // Works

Further, when I tried to output req.headers, it turns out that Express outputs all the headers in a down-case format.


I started digging down further and tried using the below code, either of these snippets work

req.header('X-Master-Key'); // Works

// -- OR

req.header('x-master-key'); // Works

So what's the issue here? Why does Express changes all header keys to down-case? Moreover, how using req.header() is different from req.headers[]?

like image 548
Mr. Alien Avatar asked Mar 25 '20 18:03

Mr. Alien


People also ask

Does Express lowercase headers?

headers['Content-Type'] will not. Why does the lower case version work? Because the Express framework, in an attempt to handle all the different possible cases (remember, HTTP will allow anything), converts everything to lower case.

How do I get HTTP request headers in node JS?

In express, we can use request. headers['header-name'], For example if you have set up a Bearer token in authorization header and want to retrieve the token, then you should write req. headers['authorization'], and you will get the string containing 'Bearer tokenString'.

What are headers in Nodejs?

The header tells the server details about the request such as what type of data the client, user, or request wants in the response. Type can be html , text , JSON , cookies or others.

What is the difference between REQ headers and REQ headers?

The different between req.headers (the object) and req.header (the function) is simply this: If you want to get a property from a Javascript object, the property name is case-sensitive. So req.headers ['content-type'] will work; req.headers ['Content-Type'] will not. Why does the lower case version work?

Why doesn't my express request header match my HTTP headers?

As you mentioned, req.headers is case-sensitive, also Express doesn't change the case, so why it doesn't match req.headers ['X-Master-Key'] ? On second look, you may be correct. I looked further and it's actually due to the node module http: HTTP headers are being converted to lower-case.

Why are HTTP headers case-insensitive in express?

The problem arises because in the HTTP protocol, headers are case-insensitive. This means that content-type, Content-Type, and coNTEnt-tYPe all refer to the same header, and the Express framework needs to be able to handle any of them. The different between req.headers (the object) and req.header (the function) is simply this:

How to get a specific header from a request object?

We can also use the header () function in request object to access any specific header. Use function <responseObject>.header (“Key”,”Value”) to set a header.


2 Answers

The problem arises because in the HTTP protocol, headers are case-insensitive. This means that content-type, Content-Type, and coNTEnt-tYPe all refer to the same header, and the Express framework needs to be able to handle any of them.

The different between req.headers (the object) and req.header (the function) is simply this:

If you want to get a property from a Javascript object, the property name is case-sensitive. So req.headers['content-type'] will work; req.headers['Content-Type'] will not. Why does the lower case version work? Because the Express framework, in an attempt to handle all the different possible cases (remember, HTTP will allow anything), converts everything to lower case.

But the developers of Express recognize that you (the developer) might be looking for Content-Type and you might not remember to convert to lower case, so they provided a function, req.header, which will take care of that for you.

So, in short:

This is recommended:

const myHeader = req.header('Content-Type');

Use whatever case you want - the function will convert it to lower case and look up the value in req.headers.

This is not recommended:

const myHeader = req.headers['Content-Type'];

If you don't use a lower-case header name, you won't get what you expect.

like image 56
Kryten Avatar answered Oct 24 '22 00:10

Kryten


The problem comes down to case-sensitivity.

When you look at the documentation for req.get (which is aliased by req.header), it states:

Returns the specified HTTP request header field (case-insensitive match). The Referrer and Referer fields are interchangeable.

The w3 standard indicates that headers should be case-insensitive:

Each header field consists of a name followed by a colon (":") and the field value. Field names are case-insensitive.

So it would appear that node http module, which express uses, just treats them all as lower-case to "save you steps" according to this github issue

You can see that the express framework req object actually utilizes the node module http:

var accepts = require('accepts');
var deprecate = require('depd')('express');
var isIP = require('net').isIP;
var typeis = require('type-is');
var http = require('http');
var fresh = require('fresh');
var parseRange = require('range-parser');
var parse = require('parseurl');

Furthermore, in the code you can see that the req.header method converts whatever you give it to lower-case:

req.get =
req.header = function header(name) {
  if (!name) {
    throw new TypeError('name argument is required to req.get');
  }

  if (typeof name !== 'string') {
    throw new TypeError('name must be a string to req.get');
  }

  var lc = name.toLowerCase();

  switch (lc) {
    case 'referer':
    case 'referrer':
      return this.headers.referrer
        || this.headers.referer;
    default:
      return this.headers[lc];
  }
};

Finally, the http module parses headers using the matchKnownFields function which automatically lower-cases any and all headers that aren't "traditional headers", in which case it is case-insensitive.

Here is the responsible snippet, that implements the behavior you are seeing:

if (lowercased) {
    return '\u0000' + field;
} else {
    return matchKnownFields(field.toLowerCase(), true);
}
like image 36
Evan Bechtol Avatar answered Oct 23 '22 23:10

Evan Bechtol