Nginx 配置指令的执行顺序(八)

前面我们详细讨论了 rewriteaccess 和 content 这三个最为常见的 Nginx 请求处理阶段,在此过程中,也顺便介绍了运行在这三个阶段的众多 Nginx 模块及其配置指令。同时可以看到,请求处理阶段的划分直接影响到了配置指令的执行顺序,熟悉这些阶段对于正确配置不同的 Nginx 模块并实现它们彼此之间的协同工作是非常必要的。所以接下来我们接着讨论余下的那些阶段。

前面在 (一) 中提到,Nginx 处理请求的过程一共划分为 11 个阶段,按照执行顺序依次是 post-readserver-rewritefind-configrewritepost-rewritepreaccessaccesspost-accesstry-filescontent 以及 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 变量读出的来源地址已经是经过改写过的了。

时间: 2024-08-25 11:01:05

Nginx 配置指令的执行顺序(八)的相关文章

Nginx 配置指令的执行顺序(一)

大多数 Nginx 新手都会频繁遇到这样一个困惑,那就是当同一个 location 配置块使用了多个 Nginx 模块的配置指令时,这些指令的执行顺序很可能会跟它们的书写顺序大相径庭.于是许多人选择了“试错法”,然后他们的配置文件就时常被改得一片狼藉.这个系列的教程就旨在帮助读者逐步地理解这些配置指令背后的执行时间和先后顺序的奥秘. 现在就来看这样一个令人困惑的例子:     ? location /test {    ?     set $a 32;    ?     echo $a;    

Nginx 配置指令的执行顺序(二)

我们前面已经知道,当 set 指令用在 location 配置块中时,都是在当前请求的 rewrite 阶段运行的.事实上,在此上下文中,ngx_rewrite 模块中的几乎全部指令,都运行在 rewrite 阶段,包括 Nginx 变量漫谈(二) 中介绍过的 rewrite 指令.不过,值得一提的是,当这些指令使用在 server 配置块中时,则会运行在一个我们尚未提及的更早的处理阶段,server-rewrite 阶段. Nginx 变量漫谈(二) 中介绍过的 ngx_set_misc 模块

Nginx 配置指令的执行顺序(十一)

紧跟在 post-access 阶段之后的是 try-files 阶段.这个阶段专门用于实现标准配置指令 try_files 的功能,并不支持 Nginx 模块注册处理程序.由于 try_files 指令在许多 FastCGI 应用的配置中都有用到,所以我们不妨在这里简单介绍一下. try_files 指令接受两个以上任意数量的参数,每个参数都指定了一个 URI. 这里假设配置了 N 个参数,则 Nginx 会在 try-files 阶段,依次把前 N-1 个参数映射为文件系统上的对象(文件或者

Nginx 配置指令的执行顺序(七)

来看一个 ngx_static 模块服务磁盘文件的例子.我们使用下面这个配置片段:     location / {        root /var/www/;    } 同时在本机的 /var/www/ 目录下创建两个文件,一个文件叫做 index.html,内容是一行文本 this is my home:另一个文件叫做 hello.html,内容是一行文本 hello world. 同时注意这两个文件的权限设置,确保它们都对运行 Nginx worker 进程的系统帐户可读. 现在来通过

NGINX openrestry(指令的执行顺序)

Nginx的指令的执行顺序: 一.post-read 二.server-rewrite ngx_rewrite模块的set指令和rewrite指令(前提在server里面配置时) 三.find-config 四.rewrite ngx_rewrite模块的set指令和rewrite指令(前提在location里面配置时) ngx_set_misc模块的set_unescape_uri指令 ngx_lua模块的set_by_lua指令 rewrite tail: ngx_headers_more模

Nginx 配置指令location 匹配符优先级和安全问题【转】

Nginx配置指令location匹配符优先级和安全问题 使用nginx 很久了,它的性能高,稳定性表现也很好,得到了很多人的认可.特别是它的配置,有点像写程序一样,每行命令结尾一个";"号,语句块用"{}"括起来.配制好,直接nginx -t 检查配制情况,配制成功,直接运行:service nginx reload.服务器没有任何宕机情况下,实现平稳修改配置.最近一直在做location 配置,遇到优先级别问题(如果配置不当可能存在安全隐患哦),以下是个人学习一

Nginx配置指令try_files

try_files指令是按顺序检测文件的存在性,并且返回第一个找到文件的内容,如果第一个找不到就会自动找第二个,依次查找.其实现的是内部跳转.以下举例说明: 案例1(跳转到变量): server {   listen 8000;   server_name 121.10.143.66;   root html;   index index.html index.php; location /abc { try_files /4.html /5.html @qwe;      --检测文件4.ht

转:Nginx配置指令location匹配符优先级和安全问题

转:http://www.jb51.net/article/47761.htm 使用nginx 很久了,它的性能高,稳定性表现也很好,得到了很多人的认可.特别是它的配置,有点像写程序一样,每行命令结尾一个";"号,语句块用"{}"括起来. 配制好,直接nginx -t 检查配制情况,配制成功,直接运行:service nginx reload .服务器没有任何宕机情况下,实现平稳修改配置 最近一直在做location 配置,遇到优先级别问题(如果配置不当可能存在安全

JFinal 配置类 方法执行顺序

1.public void configConstant(Constants me) 常量配置方法,一般 在里面 读取 配置文件 2.public void configRoute(Routes me) 配置路由,如下 me.add("/", IndexController.class, "/index"); // 第三个参数为该Controller的视图存放路径 me.add("/blog", BlogController.class); //