前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Nginx09】Nginx学习:HTTP核心模块(六)请求头处理

【Nginx09】Nginx学习:HTTP核心模块(六)请求头处理

作者头像
硬核项目经理
发布2023-09-07 09:06:54
7800
发布2023-09-07 09:06:54
举报
文章被收录于专栏:硬核项目经理的专栏

Nginx学习:HTTP核心模块(六)请求头处理

对于一个 HTTP 应用来说,最重要的其实就是 HTTP 的两个核心功能,一个是请求,一个就是响应。而对于一个 Web 应用服务器来说,响应通常是静态文件或者是动态程序代码来完成,围绕响应的配置指令大部分以缓存优化为主。从这里也能看出,在 Nginx 这种应用服务中,请求相关的内容会更多一些,因为我们要面对的,要对接的,就是从外部不断发过来的请求。

今天,我们先了解一下请求头相关的配置指令。

请求头

通用的 HTTP 请求头相关的配置主要也是大小、超时时间等等。它们都可以配置在 http、server 下面,我们一个一个来看下。

client_header_buffer_size

用于设置读取客户端请求头部的缓冲容量。

代码语言:javascript
复制
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(容量) 。

代码语言:javascript
复制
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 。

代码语言:javascript
复制
// 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 的错误。

代码语言:javascript
复制
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 错误。或者直接一个大的请求头。下面这样的请求也会报错。

代码语言:javascript
复制
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 ,上面的请求都可以正常访问了,接下来我们测另外两种情况。

代码语言:javascript
复制
large_client_header_buffers 2 512;

先测试第二个条件,请求头中的一个请求项超过一块缓冲的容量,也就是有一个请求头项的大小超过 512 字节就可以了。

代码语言:javascript
复制
GET http://192.168.56.88/
....
LongHeader: abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcde
....

正好 512 个字节,直接报 400 Request Header Or Cookie Too Large 错误。

最后,我们再测试请求行,如果超长了,会不会返回 414 错误。

代码语言:javascript
复制
GET http://192.168.56.88/?bigparams=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr

使用这个请求,正好卡在报错的长度节点上,会返回 414 Request-URI Too Large 错误。

现在你应该了解了吧,如果我们在日常的应用中出现了 400 或者 414 的报错信息,可以来检查一下这两个的配置是否有问题。

client_header_timeout

定义读取客户端请求头部的超时时间。

代码语言:javascript
复制
client_header_timeout time;

默认值是 60s 如果客户端在这段时间内没有传送完整的头部到 Nginx ,Nginx 将返回错误 408 (Request Time-out) 到客户端。和 client_body_timeout 一样,不知道咋测,但这里给出了一个 408 的错误码,如果发现了这个码的错误信息,可以过来尝试调大 client_header_timeout 和 client_body_timeout 数值,或者查查接收不到头部信息的原因。

max_ranges

如果请求中含有字节范围的请求头,这条指令可以限制此范围允许的最大值。

代码语言:javascript
复制
max_ranges number;

如果请求头的值超过此限制,将按请求未携带此请求头的情况处理。 默认nginx对此不做限制。设置为 0 将使 Nginx 完全不支持 HTTP 字节范围特性。

啥意思呢?其实我也没看明白,那么咱们就来做实验。先构造请求头,也就是加上 Range 请求头。

代码语言:javascript
复制
GET http://192.168.56.88/

…………
Range: bytes=0-100,100-200,200-300
…………

直接请求的话,服务器会返回 206 Partial Content 状态码。这个是 HTTP 的一种分段获取部分资源的状态码。具体的内容不清楚的同学可以自己查阅一下相关的资料哦。

目前是默认的情况,接下来我们配置一下 max_ranges ,先指定为一个 0 。

代码语言:javascript
复制
// nginx.conf
……
server {
 max_ranges 0;
 ……
}
……

重载配置后我们在客户端重新请求,会发现返回的状态码变成了 200 ,也就是说设置为 0 将使 Nginx 完全不支持 HTTP 字节范围特性这一点被我们证实了。接下来,再将它设置成 2 。

代码语言:javascript
复制
max_ranges 2;

再次请求后会发现返回的状态码还是 200 ,那么我们再将它调到 3 试一下,可以看到,现在又正常返回 206 了。现在你知道这个配置项的作用了吧。影响的就是 Range 请求头中范围项的数量,默认不限制就是只要有这个头就返回 206 ,如果设置为 0 ,就不管有没有都返回 200 ,如果指定为具体的数字,就是根据 Range 中的范围项数量(0-100表示一项)。

underscores_in_headers

允许或禁止在客户端请求头中使用下划线。

代码语言:javascript
复制
underscores_in_headers on | off;

默认是 off ,如果禁止,含有下划线的请求头将被标志为非法请求头并接受 ignore_invalid_headers 指令的处理。可以在默认主机的 server 配置级别定义此命令。这样,指令设置将覆盖监听同一地址和端口的所有虚拟主机。我们结合下面的配置指令一起看。

ignore_invalid_headers

控制是否忽略非法的请求头字段名。

代码语言:javascript
复制
ignore_invalid_headers on | off;

默认 on ,合法的名字是由英文字母、数字和连字符组成,当然也可以包含下划线 (由underscores_in_headers指令控制)。本指令可以在默认虚拟主机的 server 配置层级中定义一次,那么这个值在监听在相同地址和端口的所有虚拟主机上都生效。

好了,来测试一下,我们需要先把 PHP 环境配上,或者你是使用其它语言也可以配上其它语言的 Nginx 环境。然后打印一下请求头中的信息。

代码语言:javascript
复制
// 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 文件。

代码语言:javascript
复制
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 中看到打印出来的信息了。

代码语言:javascript
复制
// http://192.168.56.88/1.php
…………
[HTTP_TEST_UNDERLINE] => 123
…………

总结

东西其实不多,都是在围绕着这六个配置指令在进行测试。而且还有一些都不知道咋测,就像之前的文章中说过的,有接触过的小伙伴记得留言评论哦。

请求的内容还有一部分,就是请求体以及请求限流,这两个我们合在一起下篇文章一起学习。

参考文档:

http://nginx.org/en/docs/http/ngx_http_core_module.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-07-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农老张 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Nginx学习:HTTP核心模块(六)请求头处理
    • 请求头
      • client_header_buffer_size
      • large_client_header_buffers
      • client_header_timeout
      • max_ranges
      • underscores_in_headers
      • ignore_invalid_headers
    • 总结
    相关产品与服务
    腾讯云服务器利旧
    云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档