Nginx无法接收带下划线的header键值

in 互联网技术 with 0 comment  访问: 4,775 次

现象

昨天跟迭代新版告警平台,把告警数据发送到告警平台的API接口,但是数据发送器始终报如下错误:

11:59:22.819 [alertSystemTaskJobPool_169-thread-3] ERROR c.d.p.common.util.MetaDataUtil - Error in sending raw data, result is: {"errcode":10000,"errmsg":"The request does not contain a access-key."}

字面理解的意思就是这个请求不包含一个access-key.

分析原因

开发通过数据发送器的log,发现已经从config中读取到了access-key的值,但是发送到告警平台的API接口发送失败,然后查看告警平台API接口服务,发现传递过来的header中access-key为空。

整体平台工作架构如下:
nginx-header.png

如上图所示,可以知道SendData从配置中读取到access-key的配置信息,加入到header中的key键值是access_key

默认nginx是不能转发带_的header信息的,为什么不能支持下划线呢,因为nginx的源码中默认判定就是不合法的:

rc = ngx_http_parse_header_line(r, r->header_in, cscf->underscores_in_headers); 
if (r->invalid_header && cscf->ignore_invalid_headers) 

在ngx_http_parse_header_line() 函数中

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;
                }

if (allow_underscores)中你可以看出nginx对header name的字符做了限制,默认 underscores_in_headers 为off,表示如果header name中包含下划线,则忽略掉。

解决问题

好了现在问题已经很明显了,所以解决应该很easy了。这种问题解决方法都可以双向考虑,1是把传递的header name合法了,2是让nginx接收不合法的header name,所以解决方法如下:

  1. 让开发把传递的access_key 改为 access-key, 一般header的name都是-来拼接的,比如User-Agent
  2. 运维在nginx.conf配置文件中的http {} 部分中 添加 underscores_in_headers on;配置项

总结

运维如何在日常工作中避免这种问题,这里给出如下几点建议:

  1. 运维要求开发传递的header中的键值不要带_
  2. 统一环境,不要QA不用nginx代理,beta/prod用nginx代理,让测试在QA环境规避了这种问题
  3. 图省事运维统一线上nginx开启underscores_in_headers配置项

关于第三条,最好不要这么做,还是去跟开发沟通,让他们形成良好的开发习惯,提升规范意识。

参考:HTTP Message: https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html

WeZan