【Nginx10】Nginx学习:HTTP核心模块(七)请求体及请求限流

Nginx学习:HTTP核心模块(七)请求体及请求限流

对于一个请求来说,请求行、请求头、请求体共同构成了它的整体。不过如果仅仅是 GET 请求的话,其实一般会忽略掉请求体。但是,现在大部分的伪 RESTful 开发风格,基本上已经变成了全部都是 POST 的天下了。特别是小型公司,不管前后端分离还是小程序、APP,一套 POST 走天下。

这也不怪我们懒,或者不规范,小公司毕竟是以成本,以效率来搏命的,即使是我自己弄一些小东西,也只是想着怎么简单怎么来,不会去考虑那么复杂的实现。也正因此,POST 中请求体的部分确实是现在非常重要的内容。下面我们来详细看看相关的配置都有哪些。另外,请求限流部分的内容是我之前从来没接触过的,虽说也看过一点相关的知识,知道一些什么令牌桶之类的名词,但确实从没有自己写过。因此,请求限流部分也只是简单地测试和演示,没法给出更详细的原理及解释。

请求正文

请求正文,指的就是发来的请求中,body 部分的内容,也就是我们常说的 POST 请求的请求体部分。这一部分的配置主要是请求体的大小、超时时间、缓冲区等等。请求正文相关的配置项都可以用于 http、server、location 各个模块中。

client_body_buffer_size

设置读取客户端请求正文的缓冲容量。

client_body_buffer_size size;

如果请求正文大于缓冲容量,整个正文或者正文的一部分将写入临时文件。缓冲大小默认等于两块内存页的大小,在x86平台、其他 32 位平台和 x86-64 平台,这个值是8K。在其他 64 位平台,这个值一般是 16K 。

我们和下面的配置一起测试这个配置指令。

client_body_temp_path

定义存储客户端请求正文的临时文件的目录,没错,就是上面的超出 client_body_buffer_size 设置大小的数据所保存的临时文件的位置。默认情况下,它是位于当前运行的 Nginx 程序目录下的 client_body_temp ,比如我这里就是在这里:

[root@localhost nginx]# pwd
/usr/local/nginx
[root@localhost nginx]# ll
total 0
drwx------. 2 www  root  6 Jul 13 23:35 client_body_temp

它的配置参数是这样的。

client_body_temp_path path [level1 [level2 [level3]]];

这个 path 写相对路径或者绝对路径都可以,如果是相对路径,那么它对应的路径就是运行的 Nginx 程序所在的目录,和日志那些一样。参数后面的 level1 之类的参数,表示的是子目录的结构,最多可以支持三层,比如下面这样的配置。

client_body_temp_path /spool/nginx/client_temp 1 2;

存储临时文件的路径就是:

/spool/nginx/client_temp/7/45/00000123457

client_body_in_file_only

这个配置是用于决定 Nginx 是否将客户端请求正文整个写入到临时文件当中。

client_body_in_file_only on | clean | off;

当它的配置指令值设置为 on 时,请求处理结束后不会删除临时文件。当指令值设置为 clean 时,请求处理结束后会删除临时文件。设置为 off 就是不记录到文件中啦!默认值是 off 。

好了,结合上面三个配置,我们进行一波测试。

// nginx.conf
#client_body_buffer_size 10;
client_body_temp_path client_body_temptest;
client_body_in_file_only on;

先忽略第一个,因为我们开启了 client_body_in_file_only ,所以所有的请求体中的内容都会被记录。指定的目录是当前运行 Nginx 的目录下面的 client_body_temptest 目录,其实就是给默认目录后面加了个 test 。接着,咱们还需要定义一个可以发送 POST 请求的动态页面,由于目前的环境还没有安装 PHP ,所以咱们就随便代理一个地址。(如果直接使用 POST 请求静态页面,会报出 405 错误,Nginx 默认是禁止 POST 静态页面的)

location /request_body {proxy_pass http://localhost:8001;
}

注意哦,这是我们随便代理的,8001 是不存在的,因此直接访问这个页面是会报错的。接下来,用 Postman 发送一个 Post 请求,使用哪种参数形式都可以,这里我使用的是 raw 。

请求之后,就可以看到 Nginx 的运行目录下多了个 client_body_temptest 目录,进去后就看到了下面这样的内容。

// POST 请求 http://192.168.56.88/request_body 之后
// /usr/local/nginx/client_body_temptest
[root@localhost client_body_temptest]# ll
total 140
-rw-------. 1 www www 60453 Jul 30 03:13 0000000001

试着打开文件,你就会发现里面正是我们发送请求时写在请求体中的内容。好了,接下来怎么测 client_body_buffer_size 呢?它的意思是当请求体的大小超过了设置的缓冲值时,使用文件来保存请求体内容。注意,我们现在开启了 client_body_in_file_only ,因此所有文件都被保存下来,所以我们要注释掉它,然后再打开 client_body_buffer_size 的注释,并把值设小点。

// nginx.conf
client_body_buffer_size 10;
client_body_temp_path client_body_temptest;
#client_body_in_file_only on;

再次请求页面,在 client_body_temptest 目录下并没有生成新的文件,这要怎么验证呢?其实很简单,用 ll -a 看一下当前目录的修改时间就好了,或者再次开启 client_body_in_file_only ,会发现文件序号其实一直在增长。

// POST 请求 http://192.168.56.88/request_body 之后
// /usr/local/nginx/client_body_temptest
[root@localhost client_body_temptest]# ll -a
total 20
drwx------.  2 www  root    24 Jul 30 03:30 .
drwxr-xr-x. 11 root root   167 Jul 30 02:31 ..
-rw-------.  1 www  www  18074 Jul 30 03:13 0000000001

第一个 . 表示当前目录,看到它的修改时间发生了变化。现在你再把 client_body_buffer_size 的值调大,只要大过你测试的请求体的长度就好了。完了再测试一下,看看这个目录的修改时间会不会发生变化。如果没有发生变化,就说明请求体在缓冲中处理了,没有在这里创建过临时文件。

上面三个配置要注意的几点是:

  • client_body_temp_path 指定的目录要有 Nginx 运行用户的权限,就是我们第一篇文章中那个 user 指定的用户。

  • 出现 xxx upstream response is buffered to a temporary file xxxx while reading upstream 这样的错误,就是请求体频繁使用文件存储,可能是 client_body_buffer_size 的值设小了,可以适当调大,具体大小根据内存占用情况来确定。

  • 如果不在乎内存,就把 client_body_buffer_size 和后面要讲的 client_max_body_size 设置成一样,完全不走文件保存了。

  • client_body_in_file_only 非调试测试的情况下不要开,完全走文件肯定影响效率。

client_body_in_single_buffer

这个配置项可以确定 Nginx 将整个客户端请求正文是否保存在一块缓冲中。

client_body_in_single_buffer on | off;

它的默认值是 off ,推荐在使用 $request_body 变量时使用,可以节省引入的拷贝操作。

client_body_timeout

用于定义读取客户端请求正文的超时时间。

client_body_timeout time;

默认值是 60 秒,超时是指相邻两次读操作之间的最大时间间隔,而不是整个请求正文完成传输的最大时间。如果客户端在这段时间内没有传输任何数据,Nginx 将返回408(Request Time-out) 错误到客户端。啥意思呢?连接建立了,60s 内啥玩意也不发,直接就报错呗,这个我也不知道怎么测,所以咱们保持默认就好啦。

client_max_body_size

它设置允许客户端请求正文的最大长度,这个配置应该是比较常见的,特别是做过上传大文件的同学。

client_max_body_size size;

它的默认值是 1m ,和 PHP 中的 upload_max_filesize 以及 post_max_size类似,不过 PHP 中的默认值是 2m 。如果要上传大文件,这两边都要修改。请求的长度由 “Content-Length” 请求头指定。如果请求的长度超过设定值,nginx将返回错误 413(Request Entity Too Large)到客户端。请注意浏览器不能正确显示这个错误。设置成 0 可以使nginx不检查客户端请求正文的长度。

这个好测,直接找个大于 1m 的文件用 POST 上传到我们前面那个 /request_body 路径下,然后再修改这个值,超过我们选择的文件大小,再试一次就知道它的效果啦!或者直接设置成小的值,比如 1k ,然后随便找个大于 1k 的测试一下会不会返回 413 错误。

请求限流

Nginx 的请求限流部分,主要限的是速度,也就是流量大小。注意,这里是限流,不是限制,限制是限制请求的连接数量 ,后面还有专门的请求限制模块。限流这里最典型的案例就是百度网盘的会员和非会员的下载速度的区别。通过 Nginx 我们也可以方便地对我们自己的流量速度进行限制,我们先来看看这个配置相关的指令。

limit_except

在指定的 location 下面,配置 limit_except 后,可以按指定的 HTTP 方法进行请求限制。

limit_except method ... { ... }

在 Apache 下配置虚拟主机的时候,经常会有 Deny 和 Allow 这些相关的配置,而在 Nginx 中,其实我们通常很少去配置这个。毕竟在 Apache 下面,大部分情况下通常我们也是直接 Allow all; 的。

method 参数是用于指定不由这些限制条件进行过滤的 HTTP 方法,可选值有 GET、 HEAD、 POST、 PUT、 DELETE、 MKCOL、 COPY、 MOVE、 OPTIONS、 PROPFIND、 PROPPATCH、 LOCK、 UNLOCK 或者 PATCH。

指定 method 为 GET 方法的同时,Nginx 会自动添加 HEAD 方法。那么其他 HTTP 方法的请求就会由指令引导的配置块中的ngx_http_access_module 模块和 ngx_http_auth_basic_module 模块的指令来限制访问。这两个模块我们后面会单独学习。

那么咱们就来配置一个。为了能够测试 POST 之类的请求,需要连接一下 PHP ,所以咱们就使用之前配置好的 PHP 配置。

location ~ \.php$ {root html;limit_except GET {allow 192.168.56.101;deny all;}fastcgi_pass unix:/var/sock/php-fpm/www.sock;fastcgi_index  index.php;fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;include        fastcgi_params;
}

在 html/1.php 这个文件中,我们直接打印了 $_SERVER 的信息,因此正常访问的话,会输出 PHP 这边的 SERVER 相关内容,这里就不多说了。

我们的主机是虚拟机的主机,IP 是 192.168.56.1 ,在配置中,我们 deny 了 all ,但是开放了 .101 可以访问。划重点了,上面的 GET 表示除了 GET 之外的,比如 POST 之类的请求,就会走下面的限制约束,第一次接触的小伙伴可能真的会搞反,以为是写在这里的才被限制,其实是反过来的哦,写在这里的是不被限制的。因此,在现在的情况下,.1 主机 GET 访问 http://192.168.56.88/1.php 应该是没问题了,那么 POST 访问会出现什么呢?

大家可以试试,直接返回的就是 403 Forbidden ,也就是没有权限。也就是说,deny 是生效的。现在我们再开一台虚拟机,IP 设置成 192.168.56.101 ,然后使用 CURL 请求。

// 192.168.56.101
[root@localhost ~]# curl -X POST 'http://192.168.56.88/1.php'
Array
([USER] => www[HOME] => /home/www…………
)

没有任何问题,POST 也可以正常请求,说明 allow 对 .101 这台虚拟机是生效的。有兴趣的小伙伴可以再开一台虚拟机,设置成别的 IP ,再次进行测试,看看效果怎么样。

limit_rate

接下来我们就来看看怎么限制流量,这个配置也比较简单。

limit_rate rate;

默认值是 0 ,单位是 字节/秒 ,默认 0 就表示不限制。Nginx 按连接限速,所以如果某个客户端同时开启了两个连接,那么客户端的整体速率是这条指令设置值的 2 倍。

从 1.17.0 版本开始参数值可以包含变量,如果要根据特定条件限制速率的话,它可能很有用:

map $slow $rate {1     4k;2     8k;
}limit_rate $rate;

另外我们也可以直接使用 $limit_rate 变量设置流量限制(1.17.0后不推荐)。如果想在特定条件下限制响应传输速率,可以使用这个功能:

server {if ($slow) {set $limit_rate 4k;}...
}

变量相关的内容我们在后面的文章中再详细说,一会也会简单演示一下。

最后还可以通过 “X-Accel-Limit-Rate” 响应头来完成速率限制。这种机制可以用 proxy_ignore_headers 指令和 fastcgi_ignore_headers 指令关闭。

上面全是官网的说明内容,具体的演示我们将结合下面的配置指令一起测试。

limit_rate_after

这个指令用于设置不限速传输的响应大小。

limit_rate_after size;

默认 0 ,单位是字节,当传输量大于此值时,超出部分将根据 limit_rate 的规则限速传送。

测试限流

好了,咱们来试试吧。首先得搞个大点的文件,这样传输过程才会持续一段时间,就挑个之前我录过的视频好了。把它放到之前准备好的 /usr/local/nginx/html/mp4/ 目录下并改名为 1.mp4 为了好记好测。接着就配置一个 location 。

location /limitmp4 {alias /usr/local/nginx/html/mp4/;
}

现在访问 /limitmp4/1.mp4 ,会发现速度很快,直接下载视频,速度也很惊人,毕竟咱们是在本地的虚拟机上。然后咱们就来进行限流。

location /limitmp4 {alias /usr/local/nginx/html/mp4/;limit_rate 1k;
}

配置 limit_rate 设置为 1k ,之后重载 Nginx 并进行访问。很明显,连播放都开始卡顿了,下载速度也直接变慢了。

location /limitmp4 {alias /usr/local/nginx/html/mp4/;limit_rate 1m;limit_rate_after 1000m;
}

继续加上 limit_rate_after 限制到 1000m ,limit_rate 设置为 1m ,也就是 1G 以上的文件才会限制流量,再次访问,速度又恢复到了之前的水平。现在你可以随意修改这两个参数了,比如将 limit_rate_after 改成 200m ,我们的文件有 500m ,这时限速又开始了,不过速度比限制在 1k 的时候要好很多,因为现在的传输速度在 1m 。

接下来,我们测试一下 $limit_rate 变量的限制效果。

#set $limit_rate 1k;
location /limitmp4 {alias /usr/local/nginx/html/mp4/;#limit_rate 1m;#limit_rate_after 400m;set $limit_rate 1k;
}
location /limitmp4_2 {alias /usr/local/nginx/html/mp4/;
}

直接设置一个 $limit_rate 变量,并给其赋值为 1k ,然后访问链接,速度被限制了。然后我们开启另一个 location ,速度正常,可以看到 $limit_rate 也是有作用域范围的。现在可以再打开最上面的,也就是在 server 作用域下的 $limit_rate 会发现 /limitmp4_2 也被限速成功。

最后, X-Accel-Limit-Rate 头是针对上游服务器的,也就是反向代理或者负载均衡那边返回的内容是否将对应的响应头返回给客户端的,这个不好测,资料也不多,大概了解一下就好啦。

说了这么半天,到底限流的意义何在呢?除了百度网盘那种收费的作用外,限流还可以保护我们的带宽,避免某一个连接将整台服务器的带宽占满,比如我们下载东西的时候。另外就是在大促高并发的场景下,保障后端程序带宽的稳定性,同样也是避免带宽被占用挤压影响其它业务。

将来我们在学习更多架构方面知识的时候再来详细的研究吧,目前我的认知只到这个水平,反正 Nginx 中是有这个功能的,这一点大家还是要牢记。

总结

今天的内容真正的配置指令没几个,请求正文有六个,请求限流只有三个,更多的还是在进行一些测试。毕竟都是自己之前从来没怎么配过玩过的东西。而且我发现,请求限流相关的内容还是非常有意思的,对于大文件上传下载也有了一些想法,直接用 Nginx 就可以避免带宽被某几个用户的大文件操作占满。确实还是收获满满,各位别急,后面还有好玩的东西呢,千万别错过了。

参考文档:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/6702.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flutter的开发环境搭建-图解

前言:Flutter作为一个移动应用开发框架,具有许多优点和一些局限性。最大的优点就是-跨平台开发:Flutter可以在iOS和Android等多个平台上进行跨平台开发,使用一套代码编写应用程序,节省开发时间和成本。 Flutter可以编…

自然语言处理NLP在Java语言的应用

什么是自然语言处理? 自然语言处理(Natural Language Processing, NLP)是计算机科学中的一个重要分支,旨在让机器能够理解、处理人类语言。 自然语言处理的技术应用 自然语言处理(Natural Language Processing, NLP…

flask、uwsgi、nginx 部署

1. 安装: yum install openssl-devel nginx -y pip3 install flask uwsgi 2. 基于flask编写例子hello.py,然后保存在/opt/txt/目录下: from flask import Flask app Flask(__name__)app.route(/) def hello_world():return Hello World…

JVM运行时数据区——方法区、堆、栈的关系

方法区存储加载的字节码文件内的相关信息和运行时常量池,方法区可以看作是独立于Java堆的内存空间,方法区是在JVM启动时创建的,其内存的大小可以调整,是线程共享的,并且也会出现内存溢出的情况,也可存在垃圾…

vue、vuex、vue-router初学导航配合elementui及vscode快捷键

目录 一、vue资源 1.vue知识库汇总 2.vuejs组件 3.Vue.js 组件编码规范 目标 #目录 #基于模块开发

2023JAVA 架构师面试 130 题含答案:JVM+spring+ 分布式 + 并发编程》...

此文包含 Java 面试的各个方面,史上最全,苦心整理最全 Java 面试题目整理包括基JVM算法数据库优化算法数据结构分布式并发编程缓存等,使用层面广,知识量大,涉及你的知识盲点。要想在面试者中出类拔萃就要比人付出更多的…

3.18 Bootstrap 列表组(List Group)

文章目录 Bootstrap 列表组(List Group)向列表组添加徽章向列表组添加链接向列表组添加自定义内容 Bootstrap 列表组(List Group) 本章我们将讲解列表组。列表组件用于以列表形式呈现复杂的和自定义的内容。创建一个基本的列表组的…

【NetCore】02-NetCore启动过程

文章目录 Asp.NetCore启动过程1.Program类2.Start Up Asp.NetCore启动过程 1.Program类 Main函数调用CreateHostBuilder()方法,而CreateHostBuilder()返回了IHostBuilder,IHostBuilder就是应用程序启动的…

Debug Stable Diffusion webui

文章目录 SD前期预备一些惊喜TorchHijackForUnet Txt2Img 搭配 Lora 使用单独运行 txt2img.py获取所有资源代码地址参数sd model 主程序代码地址参数(同上)模型InferenceLORA应用重构并使用LORA模型用Lora重构后的网络 做 sampler后处理 以下内容是最近的学习笔记,如…

MySQL基础语法(DDL、DQL、DML、DCL)

目录 SQL通用语法以及分类 SQL通用语法 SQL语句的分类 数据库/表/列的命名规则 DDL语句 DDL设计的数据类型 数据库操作 表操作(必须先进入到数据库) DQL语句 DQL的执行顺序 基本查询 SELECT 条件查询 WHERE 分组查询 GROUP BY 排序查询 OR…

Python Flask构建微信小程序订餐系统 (十)

🔥 编辑会员信息 🔥 编辑会员信息可以通过点击会员列表操作,也可以点击会员信息详情点击进行操作 🔥 修改编程会员信息列表布局 🔥 修改 web/templates/member/index.html 文件,添加跳转到编辑会员信息的页面 web/templates/member/set.html 🔥 创建用于会员…

python机器学习(四)线性代数回顾、多元线性回归、多项式回归、标准方程法求解、线性回归案例

回顾线性代数 矩阵 矩阵可以理解为二维数组的另一种表现形式。A矩阵为三行两列的矩阵,B矩阵为两行三列的矩阵,可以通过下标来获取矩阵的元素,下标默认都是从0开始的。 A i j : A_{ij}: Aij​:表示第 i i i行,第 j j j列的元素。…

在虚拟机中安装anaconda和pytorch

首先我用的是VMware&#xff0c;ubuntu16.04. 首先建议安装anaconda,登录官网Free Download | Anaconda 下载完成后&#xff0c;来到安装文件目录处&#xff0c;打开终端&#xff0c; 然后在终端输入bash <anaconda文件名> 然后就一直enter和yes到底&#xff0c;直到安…

服务器中了Locked勒索病毒怎么解决,勒索病毒解密恢复方式与防护措施

服务器是企业重要数据存储和处理的关键设备&#xff0c;然而&#xff0c;众所周知&#xff0c;服务器系统并非完全免受网络攻击的。其中一种常见的威胁是勒索病毒&#xff0c;其中一种恶名昭彰的变种是Locked勒索病毒。Locked勒索病毒采用了对称AES与非对称RSA的加密形式&#…

曲线长度预测神经网络设计与实现

在本文中&#xff0c;我们使用深度神经网络 (DNN) 解决几何中的一个基本问题&#xff1a;曲线长度的计算。 我们从监督学习方法的示例中学习了几何属性。 由于最简单的几何对象是曲线&#xff0c;因此我们重点学习平面曲线的长度。 为此&#xff0c;重建了基本长度公理并建立了…

Microsoft发布用于 AutoML 算法和训练的 NNI v1.3

将传统的机器学习方法应用于现实世界的问题可能非常耗时。自动化机器学习 &#xff08;AutoML&#xff09; 旨在改变这种状况——通过对原始数据运行系统流程并选择从数据中提取最相关信息的模型&#xff0c;使构建和使用 ML 模型变得更加容易。 为了帮助用户以高效和自动的方…

【雕爷学编程】Arduino动手做(170)---LGT8F328P 开发板

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

【C++ 程序设计】第 1~9 章:常见知识点汇总

目录 一、C 语言简介 二、面向对象的基本概念 三、类和对象进阶 四、运算符重载 五、类的继承与派生 六、多态与虚函数 七、输入/输出流 八、文件操作 九、函数模板与类模板 一、C 语言简介 知识点名称内容C语言的发展简史★★1. C 语言是 C 语言的前身 &…

PyTorch深度学习实战(6)——神经网络性能优化技术

PyTorch深度学习实战&#xff08;6&#xff09;——神经网络性能优化技术 0. 前言1. 数据准备1.1 数据集分析1.2 数据集加载 2. 使用 PyTorch 训练神经网络2.1 神经网络训练流程2.2 PyTorch 神经网络训练 3. 缩放数据集4. 修改优化器5. 构建深层神经网络小结系列链接 0. 前言 …

ChatGPT在智能监控和安防系统中的应用如何?

ChatGPT在智能监控和安防系统中有着广泛的应用潜力。智能监控和安防系统是利用人工智能和计算机视觉技术来实现对环境的实时监控和安全保障的系统。ChatGPT作为一种通用的预训练语言模型&#xff0c;可以在智能监控和安防系统中发挥以下作用&#xff1a; 1. **智能视频监控**&…