我正在使用带有Body Parser的Express。给定以下标题键:
X-Master-Key
当我使用下面的代码片段时,它无法输出值
req.headers['X-Master-Key'] // Fails
但当上述内容更改为时,它会工作
req.headers['x-master-key'] // Works
此外,当我尝试输出req.headers
时,发现Express以小写格式输出所有标头。
我开始进一步挖掘,并尝试使用下面的代码,这两个片段中的任何一个都可以使用
req.header('X-Master-Key'); // Works
// -- OR
req.header('x-master-key'); // Works
那么这里有什么问题?为什么Express将所有标题键更改为小写?此外,使用req.header()
与使用req.headers[]
有何不同?
问题的出现是因为在HTTP协议中,标头不区分大小写。这意味着content-type
、Content-Type
和coNTEnt-tYPe
都引用相同的头,Express框架需要能够处理其中的任何一个。
req.headers
(对象(和req.header
(函数(之间的区别很简单:
如果要从Javascript对象获取属性,则属性名称区分大小写。因此req.headers['content-type']
将起作用;req.headers['Content-Type']
不会。为什么小写版本有效?因为Express框架试图处理所有不同的可能情况(记住,HTTP将允许任何内容(,它会将所有内容转换为小写。
但是Express的开发人员认识到,您(开发人员(可能正在寻找Content-Type
,而您可能不记得转换为小写,所以他们提供了一个函数req.header
,它将为您解决这个问题。
简而言之:
建议这样做:
const myHeader = req.header('Content-Type');
使用您想要的任何大小写-函数会将其转换为小写,并在req.headers
中查找值。
不建议这样做:
const myHeader = req.headers['Content-Type'];
如果您不使用小写标题名称,您将无法得到您所期望的。
问题归结为区分大小写。
当您查看req.get
(由req.header
别名(的文档时,它指出:
返回指定的HTTP请求标头字段(不区分大小写的匹配(。Referrer和Referrer字段可以互换。
w3标准指出标头应不区分大小写:
每个标题字段都由一个名称、一个冒号(":"(和字段值组成。字段名不区分大小写。
因此,express使用的节点http模块似乎只是将它们全部视为小写,以根据github问题"节省步骤">
您可以看到express
框架req
对象实际上使用了节点模块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');
此外,在代码中,您可以看到req.header
方法将您给它的任何内容转换为小写:
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];
}
};
最后,http
模块使用matchKnownFields
函数解析标头,该函数会自动降低非"传统标头"的所有标头的大小写,在这种情况下,它不区分大小写。
以下是负责的代码片段,它实现了您所看到的行为:
if (lowercased) {
return 'u0000' + field;
} else {
return matchKnownFields(field.toLowerCase(), true);
}