问题背景
在给接口做埋点的时候,需要在header里加一个参数用以区分不同类型接口。
参数名:_engine_type
本地开发没问题,但是部署到线上环境,取不到该header值。
中间件是nginx,所以猜想是nginx把header过滤了。
解决办法
nginx的http中新增 underscores_in_headers on; 配置
问题根源
underscores_in_headers 官方解释:
Syntax:underscores_in_headers on | off; Default:underscores_in_headers off; Context:http, serve;
Enables or disables the use of underscores in client request header fields. When the use of underscores is disabled, request header fields whose names contain underscores are marked as invalid and become subject to the ignore_invalid_headers directive.
If the directive is specified on the server level, its value is only used if a server is a default one. The value specified also applies to all virtual servers listening on the same address and port. http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers
大概意思就是,属性默认为off,表示如果header name中包含下划线,则忽略掉。可以通过 ignore_invalid_headers指令去约束。
也就是说解决办法还有一个:http部分增加:ignore_invalid_headers: on;
虽然知道解决办法了,处于学习目的,还是试着找找源码。
nginx源码下载:http://nginx.org/download/(.tar.gz结尾的)
既然是header,那肯定是在http模块了。
查找 /src/http/ngx_http_header_filter_module.c 无果。 查找 /src/http/ngx_http_parse.c 找到方法:ngx_http_parse_header_line:
ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
ngx_uint_t allow_underscores)
{
u_char c, ch, *p;
ngx_uint_t hash, i;
/* ... 省略 ... */
for (p = b->pos; p < b->last; p++) {
ch = *p;
switch (state) {
/* first char */
case sw_start:
r->header_name_start = p;
r->invalid_header = 0;
switch (ch) {
/* ... 省略 ... */
default:
state = sw_name;
if (ch == '_') {
if (allow_underscores) {
hash = ngx_hash(0, ch);
r->lowcase_header[0] = ch;
i = 1;
} else {
r->invalid_header = 1;
}
break;
}
/* ... 省略 ... */
break;
/* header name */
case sw_name:
/* ... 省略 ... */
if (ch == '_') {
if (allow_underscores) {
hash = ngx_hash(hash, ch);
r->lowcase_header[i++] = ch;
i &= (NGX_HTTP_LC_HEADER_LEN - 1);
} else {
r->invalid_header = 1;
}
break;
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
看不懂C,但是跟Java相似的地方也很多,大概就是:
循环遍历当前headers字符串,遇到换行符就代表结束,否则继续遍历,如果遇到下划线 _,继续判断 allow_underscores是否为true,如果允许下划线(allow_underscores=true或者1、on之类的)那么走正常逻辑,如果不允许下划线,那么 invalid_header置为1,代表无效header。
总结
虽然没有真正找到为什么要忽略下划线的原因(也许怕和nginx私有变量重名?),但是也说明nginx的代码规范,变量可以带下划线,但是header命名最好都用 - 减号连接,并且每个单词首字母大写。
比如常见请求头:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers
nginx源码解读:https://blog.csdn.net/yangyin007/article/details/82777086 nginx官方文档:http://www.nginx.cn/doc/