标题:【Nginx09】Nginx学习:HTTP核心模块(六)请求头处理
Nginx学习:HTTP核心模块(六)请求头处理
对于一个 HTTP 应用来说,最重要的其实就是 HTTP 的两个核心功能,一个是请求,一个就是响应。而对于一个 Web 应用服务器来说,响应通常是静态文件或者是动态程序代码来完成,围绕响应的配置指令大部分以缓存优化为主。从这里也能看出,在 Nginx 这种应用服务中,请求相关的内容会更多一些,因为我们要面对的,要对接的,就是从外部不断发过来的请求。
今天,我们先了解一下请求头相关的配置指令。
请求头
通用的 HTTP 请求头相关的配置主要也是大小、超时时间等等。它们都可以配置在 http、server 下面,我们一个一个来看下。
client_header_buffer_size
用于设置读取客户端请求头部的缓冲容量。
client_header_buffer_size size;
默认值是 1k ,对于大多数请求,1K的缓冲足矣。但如果请求中含有的cookie很长,或者请求来自WAP的客户端,可能请求头不能放在1K的缓冲中。 如果从请求行,或者某个请求头开始不能完整的放在这块空间中,那么 Nginx 将按照 large_client_header_buffers 指令的配置分配更多更大的缓冲来存放。
注意哦,这里和请求体不同的是,请求体会往文件里放,但请求头不会,不够了再根据其它配置申请更大的内存。毕竟请求头的内容再大也大不到像需要上传文件的请求体一样。最终它的配置其实不会导致什么影响,因为最终如果不够了它会根据 large_client_header_buffers 的配置进行申请分配,因此,我们紧接着就看看 large_client_header_buffers 的配置。
large_client_header_buffers
这个配置是设置读取客户端请求超大请求的缓冲最大 number(数量) 和每块缓冲的 size(容量) 。
large_client_header_buffers number size;
它的默认值是 4 8k 。条件包括这么几点:
HTTP 请求行的长度不能超过一块缓冲的容量,否则nginx返回错误414 (Request-URI Too Large)到客户端。
每个请求头的长度也不能超过一块缓冲的容量,否则nginx返回错误400 (Bad Request)到客户端。
(请求行+请求头) 的大小不能超过 32k(4 * 8k) 。
即使 Nginx 处理完请求后与客户端保持长连接,Nginx 也会释放这些缓冲。如果在服务器级别指定该指令,则可以使用默认服务器的值。好了,咱们来测试一下。首先配置一下 Nginx 。
// nginx.conf
……
server {
client_header_buffer_size 256;
large_client_header_buffers 1 512;
……
}
……
注意,large_client_header_buffers 第二个参数必须要大于等于 connection_pool_size 这个配置项的大小,我这里默认是 512 ,所以这里只能配置为 512 ;第一个参数也不能设置为 0 ,必须是大于 0 的数字。
接下来进行测试,现在这个情况,其实只要头部有一个大字符的参数,或者请求行(就是 URL 行)比较长,就会出 400 的错误。
GET http://192.168.56.88/?bigparams=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnop
User-Agent: PostmanRuntime/7.29.2
Accept: */*
Postman-Token: 328e2a7a-84e9-4622-9c83-2bdeb67ea94a
Host: 192.168.56.88
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
上面的请求数据试一下,正好 513 个字符,直接报 400 Request Header Or Cookie Too Large 错误。或者直接一个大的请求头。下面这样的请求也会报错。
GET http://192.168.56.88/
LongHeader: abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc
User-Agent: PostmanRuntime/7.29.2
Accept: */*
Postman-Token: 200ad116-daca-4129-81a3-c17039021865
Host: 192.168.56.88
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
上面的两个请求其实对应的是第三个条件,也就是请求行和请求头的和超过了 number * size 的大小,现在我们设置的就是 1 * 512 ,因此现在最大的大小就是 512 字节。接下来我们修改一下,将 number 改为 2 ,上面的请求都可以正常访问了,接下来我们测另外两种情况。
large_client_header_buffers 2 512;
先测试第二个条件,请求头中的一个请求项超过一块缓冲的容量,也就是有一个请求头项的大小超过 512 字节就可以了。
GET http://192.168.56.88/
....
LongHeader: abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcde
....
正好 512 个字节,直接报 400 Request Header Or Cookie Too Large 错误。
最后,我们再测试请求行,如果超长了,会不会返回 414 错误。
GET http://192.168.56.88/?bigparams=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr
使用这个请求,正好卡在报错的长度节点上,会返回 414 Request-URI Too Large 错误。
现在你应该了解了吧,如果我们在日常的应用中出现了 400 或者 414 的报错信息,可以来检查一下这两个的配置是否有问题。
client_header_timeout
定义读取客户端请求头部的超时时间。
client_header_timeout time;
默认值是 60s 如果客户端在这段时间内没有传送完整的头部到 Nginx ,Nginx 将返回错误 408 (Request Time-out) 到客户端。和 client_body_timeout 一样,不知道咋测,但这里给出了一个 408 的错误码,如果发现了这个码的错误信息,可以过来尝试调大 client_header_timeout 和 client_body_timeout 数值,或者查查接收不到头部信息的原因。
max_ranges
如果请求中含有字节范围的请求头,这条指令可以限制此范围允许的最大值。
max_ranges number;
如果请求头的值超过此限制,将按请求未携带此请求头的情况处理。 默认nginx对此不做限制。设置为 0 将使 Nginx 完全不支持 HTTP 字节范围特性。
啥意思呢?其实我也没看明白,那么咱们就来做实验。先构造请求头,也就是加上 Range 请求头。
GET http://192.168.56.88/
…………
Range: bytes=0-100,100-200,200-300
…………
直接请求的话,服务器会返回 206 Partial Content 状态码。这个是 HTTP 的一种分段获取部分资源的状态码。具体的内容不清楚的同学可以自己查阅一下相关的资料哦。
目前是默认的情况,接下来我们配置一下 max_ranges ,先指定为一个 0 。
// nginx.conf
……
server {
max_ranges 0;
……
}
……
重载配置后我们在客户端重新请求,会发现返回的状态码变成了 200 ,也就是说设置为 0 将使 Nginx 完全不支持 HTTP 字节范围特性这一点被我们证实了。接下来,再将它设置成 2 。
max_ranges 2;
再次请求后会发现返回的状态码还是 200 ,那么我们再将它调到 3 试一下,可以看到,现在又正常返回 206 了。现在你知道这个配置项的作用了吧。影响的就是 Range 请求头中范围项的数量,默认不限制就是只要有这个头就返回 206 ,如果设置为 0 ,就不管有没有都返回 200 ,如果指定为具体的数字,就是根据 Range 中的范围项数量(0-100表示一项)。
underscores_in_headers
允许或禁止在客户端请求头中使用下划线。
underscores_in_headers on | off;
默认是 off ,如果禁止,含有下划线的请求头将被标志为非法请求头并接受 ignore_invalid_headers 指令的处理。可以在默认主机的 server 配置级别定义此命令。这样,指令设置将覆盖监听同一地址和端口的所有虚拟主机。我们结合下面的配置指令一起看。
ignore_invalid_headers
控制是否忽略非法的请求头字段名。
ignore_invalid_headers on | off;
默认 on ,合法的名字是由英文字母、数字和连字符组成,当然也可以包含下划线 (由underscores_in_headers指令控制)。本指令可以在默认虚拟主机的 server 配置层级中定义一次,那么这个值在监听在相同地址和端口的所有虚拟主机上都生效。
好了,来测试一下,我们需要先把 PHP 环境配上,或者你是使用其它语言也可以配上其它语言的 Nginx 环境。然后打印一下请求头中的信息。
// nginx.conf
……
server {
location ~ \.php$ {
root html;
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
……
}
……
// html/1.php
<?php
print_r($_SEREVER);
然后,在 Postman 中构造一个请求头,并请求刚刚创建的 php 文件。
GET http://192.168.56.88/1.php
Request Headers
………………
TEST_UNDERLINE: 123
………………
目前我们还没有修改默认的配置,所以现在在响应打印的信息中,你应该看不到 TEST_UNDERLINE 这条新加的请求头信息。这就是因为默认情况下,underscores_in_headers 设置的是 off ,不启用下划线请求头,会将下划线请求头标记为非法的请求头,然后 ignore_invalid_headers 是 on ,自动忽略掉这些非常的请求头,不会将这些请求头继续向下转发。
要测试非常简单。将 underscores_in_headers 设置为 on ,或者将 ignore_invalid_headers 设置为 off ,那么就都可以在 PHP 中看到打印出来的信息了。
// http://192.168.56.88/1.php
…………
[HTTP_TEST_UNDERLINE] => 123
…………
总结
东西其实不多,都是在围绕着这六个配置指令在进行测试。而且还有一些都不知道咋测,就像之前的文章中说过的,有接触过的小伙伴记得留言评论哦。
请求的内容还有一部分,就是请求体以及请求限流,这两个我们合在一起下篇文章一起学习。
参考文档:
http://nginx.org/en/docs/http/ngx_http_core_module.html
视频链接
微信文章地址:https://mp.weixin.qq.com/s/Xb5v1vJyGf4r8xdEPeJCLw