Nginx 配置指令的执行顺序(八)
2014-12-18 15:01
85 查看
前面我们详细讨论了
前面在 (一) 中提到,Nginx 处理请求的过程一共划分为 11 个阶段,按照执行顺序依次是
最先执行的
这里的配置是让 Nginx 把那些来自
首先在本地请求一下这个
这里使用了 curl 工具的
如果在请求上例中的
如果从另一台机器访问这个
有的读者可能会问,ngx_realip 模块究竟有什么实际用途呢?为什么我们需要去改写请求的来源地址呢?答案是:当 Nginx 处理的请求经过了某个 HTTP 代理服务器的转发时,这个模块就变得特别有用。当原始的用户请求经过转发之后,Nginx 接收到的请求的来源地址无一例外地变成了该代理服务器的 IP 地址,于是 Nginx 以及 Nginx 背后的应用就无法知道原始请求的真实来源。所以,一般我们会在 Nginx 之前的代理服务器中把请求的原始来源地址编码进某个特殊的 HTTP 请求头中(例如上例中的
这里,配置语句
由于
请求
在这个例子中,虽然 set 指令写在了 ngx_realip 的配置指令之前,但仍然晚于 ngx_realip 模块执行。所以
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阶段。下面就来看这样的一个例子:
server { listen 8080; location /test { set $b "$a, world"; echo $b; } set $a hello; }
这里,配置语句
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 配置指令的执行顺序(五)
- Nginx 配置指令的执行顺序(六)
- Nginx配置指令的执行顺序
- Nginx 配置指令的执行顺序(十一)
- Nginx 配置指令的执行顺序(二)
- Nginx 配置指令的执行顺序(七)
- Nginx 配置指令的执行顺序(八)
- Nginx 配置指令的执行顺序
- Nginx 配置指令的执行顺序(十)
- Nginx 配置指令的执行顺序(三)
- Nginx 配置指令的执行顺序(一)
- nginx配置指令的执行顺序(1)转载子章亦春
- Nginx-Lua模块的执行顺序及指令
- 转载:nginx配置文件的location标签执行顺序和反向代理配置
- Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 二
- bash中profile等配置文件执行顺序
- Linux周期性任务的执行指令配置
- Nginx 关于 Rewrite 执行顺序详解