引言
之前在项目中遇到一个关于http协议header部分最大长度限制的问题,个人觉得很有意思,于是写下这篇文章记录这个问题。
http协议,超文本传输协议,HyperText Transfer Protocol,是互联网上应用最为广泛的一种网络协议,所有的WWW文件都遵守这个标准。关于http协议消息的格式,大家可以网上自行搜索,这里不再赘述。本文关注的是其header部分,如下图所示(红框标注部分):
问题原型
有一个web application提供web service,这个web application基于java开发,部署在tomcat容器上。问题是:当客户端发送一个GET请求,结果得到400的response,意思是说bad request。检查了这个request的代码实现逻辑,并没有相关input validation的逻辑,并且检查server端日志发现,request请求似乎并没有到达我们自己代码实现逻辑部分。这是为什么呢?
问题解释
遇到这个问题时,第一步就是查看server端日志,但是觉得很tricky的是,最开始并没有发现相关的日志,只是发现request并没有到达我们自己代码实现逻辑部分。后来,mina同学眼神很好,发现了如下日志:
通过日志note信息发现,该条日志在info级别下只会打印一次,之后都会是debug级别才打印,难怪之前没有注意到这条日志。
从日志信息可知,request的header部分太大,超过了tomcat允许的最大值。默认情况下,tomcat(8.0版本)允许的http请求header的最大值是8024个字节(8KB)。那为什么之前没有出现这个问题呢?原因是,项目迁移到SCP平台上之后,改成JWT token做权限校验,这个JWT token会被添加到request的header,然而JWT token一般来说都很大(平均有6k个字节左右),所以说在增加了JWT token这个header以及其他一些相关的headers之后,整个request的header部分就超过8024个字节,于是就出现了这个问题。
那么如何解决这个问题呢?可以从两个方面考虑:
增加tomcat允许http header最大值。这个配置参数maxHttpHeaderSize可以设置tomcat允许的http header最大值。
减少header的size,比如不要添加无关的header到request。
扩展
在研究这个问题的过程中,其实还有一些其他疑问。首先,一个request的转发流程大致如下:
那么,在这个流程中,为什么request在前面的部分没有出现这个问题,而这个问题出现在最后一个技术栈是java/tomcat的component呢?
原因是,每个web服务器的http header最大长度的默认值不一样,同时随语言、版本不同也会不一样。举个例子tomcat 5的http header size的默认值是4K。
我找到了其他component中对于http header size的默认值的定义:
CF Router是用Go语言实现,Go语言的http处理模块对于它的定义是默认值1MB。
App Router是用Nodejs实现,Nodejs的http处理模块对它的定义是默认值80KB。
以上两个默认值都要远远大于8KB,这也就解释了没什么问题出在最后一个component。
References
https://baike.baidu.com/item/http/243074?fromtitle=HTTP%E5%8D%8F%E8%AE%AE&fromid=1276942&fr=aladdin
http://tomcat.apache.org/tomcat-8.0-doc/config/http.html
https://tomcat.apache.org/tomcat-5.5-doc/config/http.html
http://grokbase.com/t/gg/golang-nuts/15aqc8qc9k/go-nuts-max-size-for-http-headers
https://golang.org/pkg/net/http/#pkg-constants
https://stackoverflow.com/questions/24167656/nodejs-max-header-size-in-http-request
https://github.com/nodejs/node-v0.x-archive/tree/597eb6a5aebbc2afbd76d16e568a86ed28509bc7/deps/http_parser
领取专属 10元无门槛券
私享最新 技术干货