Nginx 配置指令的执行顺序(八)
前面我们详细讨论了 rewrite
、access
和 content
这三个最为常见的 Nginx 请求处理阶段,在此过程中,也顺便介绍了运行在这三个阶段的众多 Nginx 模块及其配置指令。同时可以看到,请求处理阶段的划分直接影响到了配置指令的执行顺序,熟悉这些阶段对于正确配置不同的 Nginx 模块并实现它们彼此之间的协同工作是非常必要的。所以接下来我们接着讨论余下的那些阶段。
前面在 (一) 中提到,Nginx 处理请求的过程一共划分为 11 个阶段,按照执行顺序依次是 post-read
、server-rewrite
、find-config
、rewrite
、post-rewrite
、preaccess
、access
、post-access
、try-files
、content
以及 log
.
最先执行的 post-read
阶段在 Nginx 读取并解析完请求头(request headers)之后就立即开始运行。这个阶段像前面介绍过的 rewrite
阶段那样支持 Nginx 模块注册处理程序。比如标准模块 ngx_realip 就在post-read
阶段注册了处理程序,它的功能是迫使 Nginx 认为当前请求的来源地址是指定的某一个请求头的值。下面这个例子就使用了 ngx_realip 模块提供的 set_real_ip_from 和 real_ip_header 这两条配置指令:
server {
listen 8080;
set_real_ip_from 127.0.0.1;
real_ip_header X-My-IP;
location /test {
set $addr $remote_addr;
echo "from: $addr";
}
}
这里的配置是让 Nginx 把那些来自 127.0.0.1
的所有请求的来源地址,都改写为请求头 X-My-IP
所指定的值。同时该例使用了标准内建变量 $remote_addr 来输出当前请求的来源地址,以确认是否被成功改写。
首先在本地请求一下这个 /test
接口:
$ curl -H 'X-My-IP: 1.2.3.4' localhost:8080/test
from: 1.2.3.4
这里使用了 curl 工具的 -H
选项指定了额外的 HTTP 请求头 X-My-IP: 1.2.3.4
. 从输出可以看到,$remote_addr 变量的值确实在 rewrite
阶段就已经成为了 X-My-IP
请求头中指定的值,即 1.2.3.4
. 那么 Nginx 究竟是在什么时候改写了当前请求的来源地址呢?答案是:在 post-read
阶段。由于 rewrite
阶段的运行远在 post-read
阶段之后,所以当在 location
配置块中通过 set 配置指令读取 $remote_addr 内建变量时,读出的来源地址已经是经过 post-read
阶段篡改过的。
如果在请求上例中的 /test
接口时没有指定 X-My-IP
请求头,或者提供的 X-My-IP
请求头的值不是合法的 IP 地址,那么 Nginx 就不会对来源地址进行改写,例如:
$ curl localhost:8080/test
from: 127.0.0.1
$ curl -H 'X-My-IP: abc' localhost:8080/test
from: 127.0.0.1
如果从另一台机器访问这个 /test
接口,那么即使指定了合法的 X-My-IP
请求头,也不会触发 Nginx 对来源地址进行改写。这是因为上例已经使用 set_real_ip_from 指令规定了来源地址的改写操作只对那些来自127.0.0.1
的请求生效。这种过滤机制可以避免来自其他不受信任的地址的恶意欺骗。当然,也可以通过set_real_ip_from 指令指定一个 IP 网段(利用 (三) 中介绍过的“CIDR 记法”)。此外,同时配置多个set_real_ip_from 语句也是允许的,这样可以指定多个受信任的来源地址或地址段。下面是一个例子:
set_real_ip_from 10.32.10.5;
set_real_ip_from 127.0.0.0/24;
有的读者可能会问,ngx_realip 模块究竟有什么实际用途呢?为什么我们需要去改写请求的来源地址呢?答案是:当 Nginx 处理的请求经过了某个 HTTP 代理服务器的转发时,这个模块就变得特别有用。当原始的用户请求经过转发之后,Nginx 接收到的请求的来源地址无一例外地变成了该代理服务器的 IP 地址,于是 Nginx 以及 Nginx 背后的应用就无法知道原始请求的真实来源。所以,一般我们会在 Nginx 之前的代理服务器中把请求的原始来源地址编码进某个特殊的 HTTP 请求头中(例如上例中的 X-My-IP
请求头),然后再在 Nginx 一侧把这个请求头中编码的地址恢复出来。这样 Nginx 中的后续处理阶段(包括 Nginx 背后的各种后端应用)就会认为这些请求直接来自那些原始的地址,代理服务器就仿佛不存在一样。正是因为这个需求,所以 ngx_realip 模块才需要在第一个处理阶段,即 post-read
阶段,注册处理程序,以便尽可能早地改写请求的来源。
post-read
阶段之后便是 server-rewrite
阶段。我们曾在 (二) 中简单提到,当 ngx_rewrite 模块的配置指令直接书写在 server
配置块中时,基本上都是运行在 server-rewrite
阶段。下面就来看这样的一个例子:
这里,配置语句 set $a hello
直接写在了 server
配置块中,因此它就运行在 server-rewrite
阶段。而server-rewrite
阶段要早于 rewrite
阶段运行,因此写在 location
配置块中的语句 set $b "$a, world"
便晚于外面的 set $a hello
语句运行。该例的测试结果证明了这一点:
$ curl localhost:8080/test
hello, world
由于 server-rewrite
阶段位于 post-read
阶段之后,所以 server
配置块中的 set 指令也就总是运行在ngx_realip 模块改写请求的来源地址之后。来看下面这个例子:
server {
listen 8080;
set $addr $remote_addr;
set_real_ip_from 127.0.0.1;
real_ip_header X-Real-IP;
location /test {
echo "from: $addr";
}
}
请求 /test
接口的结果如下:
$ curl -H 'X-Real-IP: 1.2.3.4' localhost:8080/test
from: 1.2.3.4
在这个例子中,虽然 set 指令写在了 ngx_realip 的配置指令之前,但仍然晚于 ngx_realip 模块执行。所以$addr
变量在 server-rewrite
阶段被 set 指令赋值时,从 $remote_addr 变量读出的来源地址已经是经过改写过的了。
Nginx 配置指令的执行顺序(八)的更多相关文章
- Nginx 配置指令的执行顺序(五)
Nginx 的 content 阶段是所有请求处理阶段中最为重要的一个,因为运行在这个阶段的配置指令一般都肩负着生成“内容”(content)并输出 HTTP 响应的使命.正因为其重要性,这个阶段的配 ...
- Nginx 配置指令的执行顺序(一)
大多数 Nginx 新手都会频繁遇到这样一个困惑,那就是当同一个 location 配置块使用了多个 Nginx 模块的配置指令时,这些指令的执行顺序很可能会跟它们的书写顺序大相径庭.于是许多人选择了 ...
- Nginx配置指令的执行顺序
rewrite阶段 rewrite阶段是一个比较早的请求处理阶段,这个阶段的配置指令一般用来对当前请求进行各种修改(比如对URI和URL参数进行改写),或者创建并初始化一系列后续处理阶段可能需要的Ng ...
- Nginx 配置指令的执行顺序(二)
我们前面已经知道,当 set 指令用在 location 配置块中时,都是在当前请求的 rewrite 阶段运行的.事实上,在此上下文中,ngx_rewrite 模块中的几乎全部指令,都运行在 rew ...
- Nginx 配置指令的执行顺序(十)
运行在 post-rewrite 阶段之后的是所谓的 preaccess 阶段.该阶段在 access 阶段之前执行,故名preaccess. 标准模块 ngx_limit_req 和 ngx_lim ...
- Nginx 配置指令的执行顺序(六)
前面我们在 (五) 中提到,在一个 location 中使用 content 阶段指令时,通常情况下就是对应的 Nginx 模块注册该 location 中的“内容处理程序”.那么当一个 locati ...
- Nginx 配置指令的执行顺序(三)
如前文所述,除非像 ngx_set_misc 模块那样使用特殊技术,其他模块的配置指令即使是在 rewrite 阶段运行,也不能和 ngx_rewrite 模块的指令混合使用.不妨来看几个这样的例子. ...
- Nginx 配置指令的执行顺序
在一个 location 中使用 content 阶段指令时,通常情况下就是对应的 Nginx 模块注册该 location 中的“内容处理程序”.那么当一个 location 中未使用任何 cont ...
- Nginx 配置指令的执行顺序(十一)
紧跟在 post-access 阶段之后的是 try-files 阶段.这个阶段专门用于实现标准配置指令 try_files 的功能,并不支持 Nginx 模块注册处理程序.由于 try_files ...
随机推荐
- 居然因为交换错了好几把。。。。,还有坑点是num1可以大于num2
完数 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submissi ...
- Logging in Java
Common logging: Log4j1仅仅作为一个实际的日志框架,commons-logging作为门面,统一各种日志框架的混乱格局 基本的commons logging Dependency: ...
- BZOJ 1062 糖果雨
http://www.lydsy.com/JudgeOnline/problem.php?id=1062 思路:找到平行四边形以后,变换坐标:y->y-kx,k为斜率,这样变成了矩形,然后只要二 ...
- 微控制器(MCU)破解秘笈--背景知识
2.1 硅芯片安全措施的演变 工业控制器的硬件安全措施与嵌入式系统同时开始发展.三十年前的系统是由分离的部件如CPU,ROM,RAM,I/O缓冲器,串口和其他通信与控制接口组成的.如图2-1所示: 图 ...
- 在Qt中怎样显示ASCII码大于127的字符
前段时间要显示“≤”符号找了挺久没找到方法,后面发现用以下方法可以解决: ushort gd[]={8805,0}; QString gteq=QString::fromUtf16(gd); 得 ...
- C# System.Object基类
System.Object 基类 System.Object在.Net中是所有类型的基类,任何类型都直接或间接地继承自System.Object.没有指定基类的类型都默认继承于System.Objec ...
- Linux APP源码级编译安装
首先需要了解下tar包. 以下文章作出解释了: http://www.cnblogs.com/laipDIDI/articles/2214270.html http://baike.baidu.com ...
- UESTC_Tournament CDOJ 124
A sports company is planning to advertise in a tournament. It is a single round-robin tournament, th ...
- HBase的基本操作
1.输入hbase shell进入HBase shell
- A Simple Problem with Integers(100棵树状数组)
A Simple Problem with Integers Time Limit: 5000/1500 MS (Java/Others) Memory Limit: 32768/32768 K ...