运营反馈 Nginx 报 400 错误,具体点说:Request Header Or Cookie Too Large。其实随便搜搜就知道可以通过加大 client_header_buffer_size 和 large_client_header_buffers 来解决问题,不过这里面有一些细节值得讨论,正所谓:知其然,知其所以然。

 

首先,让我们想想为何 Nginx 不能用一个指令来搞定问题,而要用两个指令?为了搞清楚这个问题,我们不妨先看看官方文档的描述:

  • client_header_buffer_size: Sets buffer size for reading client request header. For most requests, a buffer of 1K bytes is enough. However, if a request includes long cookies, or comes from a WAP client, it may not fit into 1K. If a request line or a request header field does not fit into this buffer then larger buffers, configured by the large_client_header_buffers directive, are allocated.
  • large_client_header_buffers: Sets the maximum number and size of buffers used for reading large client request header. A request line cannot exceed the size of one buffer, or the 414 (Request-URI Too Large) error is returned to the client. A request header field cannot exceed the size of one buffer as well, or the 400 (Bad Request) error is returned to the client. Buffers are allocated only on demand. By default, the buffer size is equal to 8K bytes. If after the end of request processing a connection is transitioned into the keep-alive state, these buffers are released.

大概意思是说 Nginx 使用 client_header_buffer_size 缓存客户端的请求头,一旦空间不够了,就通过 large_client_header_buffers 按需扩容。这样做可以平衡资源和性能。

比如说大部分请求头的大小在 2K 以内,小部分的请求头在 10K 左右,此时理论上我们可以通过调整 client_header_buffer_size 到 10K 来解决问题,不过这样的话无疑浪费了宝贵的内存,更好的方法是调整 client_header_buffer_size 到 2K 满足大部分请求头的需求,至于小部分 10K 的请求头,则通过调整 large_client_header_buffers 来满足。

其次,让我们看看如何了解请求头的情况,这里试试一个名为 ngrep 的小工具:


Request Header Or Cookie Too Large_客户端

ngrep


下面是我秀 awk 的时刻了,比如统计一下请求头都有多长:

shell> ngrep -W byline 'GET /' 'tcp and dst port 80' |
awk -v RS="#+" -v FS="\n" '{ print length() }'


再比如查询一下大于 1K 的请求头:

shell> ngrep -W byline 'GET /' 'tcp and dst port 80' |
awk -v RS="#+" -v FS="\n" 'length() > 1000'