`
风过无声
  • 浏览: 92072 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Nginx 配置指令的执行顺序(十)11个阶段3(转载)

 
阅读更多

转载自 http://blog.sina.com.cn/openresty

 

运行在 post-rewrite 阶段之后的是所谓的 preaccess 阶段。该阶段在 access 阶段之前执行,故名 preaccess.

 

    标准模块 ngx_limit_req 和 ngx_limit_zone 就运行在此阶段,前者可以控制请求的访问频度,而后者可以限制访问的并发度。这里我们仅仅和它们打个照面,后面还会有机会专门接触到这两个模块。

 

    前面反复提到的标准模块 ngx_realip 其实也在这个阶段注册了处理程序。有些读者可能会问:“这是为什么呢?它不是已经在 post-read 阶段注册处理程序了吗?”我们不妨通过下面这个例子来揭晓答案:

    server {

        listen 8080;

 

        location /test {

            set_real_ip_from 127.0.0.1;

            real_ip_header X-Real-IP;

 

            echo "from: $remote_addr";

        }

    }

与先看前到的例子相比,此例最重要的区别在于把 ngx_realip 的配置指令放在了 location 配置块中。前面我们介绍过,Nginx 匹配 location 的动作发生在 find-config 阶段,而 find-config 阶段远远晚于 post-read 阶段执行,所以在 post-read 阶段,当前请求还没有和任何 location 相关联。在这个例子中,因为 ngx_realip 的配置指令都写在了 location 配置块中,所以在 post-read 阶段,ngx_realip 模块的处理程序没有看到任何可用的配置信息,便不会执行来源地址的改写工作了。

 

    为了解决这个难题,ngx_realip 模块便又特意在 preaccess 阶段注册了处理程序,这样它才有机会运行 location 块中的配置指令。正是因为这个缘故,上面这个例子的运行结果才符合直觉预期:

    $ curl -H 'X-Real-IP: 1.2.3.4' localhost:8080/test

    from: 1.2.3.4

不幸的是,ngx_realip 模块的这个解决方案还是存在漏洞的,比如下面这个例子:

    server {

        listen 8080;

 

        location /test {

            set_real_ip_from 127.0.0.1;

            real_ip_header X-Real-IP;

 

            set $addr $remote_addr;

            echo "from: $addr";

        }

    }

这里,我们在 rewrite 阶段将 $remote_addr 的值保存到了用户变量 $addr 中,然后再输出。因为 rewrite 阶段先于 preaccess 阶段执行,所以当 ngx_realip 模块尚未在 preaccess 阶段改写来源地址时,最初的来源地址就已经在 rewrite 阶段被读取了。上例的实际请求结果证明了我们的结论:

    $ curl -H 'X-Real-IP: 1.2.3.4' localhost:8080/test

    from: 127.0.0.1

输出的地址确实是未经改写过的。Nginx 的“调试日志”可以进一步确认这一点:

    $ grep -E 'http script (var|set)|realip' logs/error.log

    [debug] 32488#0: *1 http script var: "127.0.0.1"

    [debug] 32488#0: *1 http script set $addr

    [debug] 32488#0: *1 realip: "1.2.3.4"

    [debug] 32488#0: *1 realip: 0100007F FFFFFFFF 0100007F

    [debug] 32488#0: *1 http script var: "127.0.0.1"

其中第一行调试信息

    [debug] 32488#0: *1 http script var: "127.0.0.1"

是 set 语句读取 $remote_addr 变量时产生的。信息中的字符串 "127.0.0.1" 便是 $remote_addr 当时读出来的值。

 

    而第二行调试信息

    [debug] 32488#0: *1 http script set $addr

则显示我们对变量 $addr 进行了赋值操作。

 

    后面两行信息

    [debug] 32488#0: *1 realip: "1.2.3.4"

    [debug] 32488#0: *1 realip: 0100007F FFFFFFFF 0100007F

是 ngx_realip 模块在 preaccess 阶段改写当前请求的来源地址。我们看到,改写后的新地址确实是期望的 1.2.3.4. 但很明显这个操作发生在 $addr 变量赋值之后,所以已经太迟了。

 

    而最后一行信息

    [debug] 32488#0: *1 http script var: "127.0.0.1"

则是 echo 配置指令在输出时读取变量 $addr 时产生的,我们看到它的值是改写前的来源地址。

 

    看到这里,有的读者可能会问:“如果 ngx_realip 模块不在 preaccess 阶段注册处理程序,而在 rewrite 阶段注册,那么上例不就可以工作了?”答案是:不一定。因为 ngx_rewrite 模块的处理程序也同样注册在 rewrite 阶段,而前面我们在 (二) 中特别提到,在这种情况下,不同模块之间的执行顺序一般是不确定的,所以 ngx_realip 的处理程序可能仍然在 set 语句之后执行。

 

    一个建议是:尽量在 server 配置块中配置 ngx_realip 这样的模块,以避免上面介绍的这种棘手的例外情况。

 

    运行在 preaccess 阶段之后的则是我们的另一个老朋友,access 阶段。前面我们已经知道了,标准模块 ngx_access、第三方模块 ngx_auth_request 以及第三方模块 ngx_lua 的 access_by_lua 指令就运行在这个阶段。

 

    access 阶段之后便是 post-access 阶段。从这个阶段的名字,我们也能一眼看出它是紧跟在 access 阶段后面执行的。这个阶段也和 post-rewrite 阶段类似,并不支持 Nginx 模块注册处理程序,而是由 Nginx 核心自己完成一些处理工作。post-access 阶段主要用于配合 access 阶段实现标准 ngx_http_core 模块提供的配置指令 satisfy 的功能。

 

    对于多个 Nginx 模块注册在 access 阶段的处理程序,satisfy 配置指令可以用于控制它们彼此之间的协作方式。比如模块 A 和 B 都在 access 阶段注册了与访问控制相关的处理程序,那就有两种协作方式,一是模块 A 和模块 B 都得通过验证才算通过,二是模块 A 和模块 B 只要其中任一个通过验证就算通过。第一种协作方式称为 all 方式(或者说“与关系”),第二种方式则被称为 any 方式(或者说“或关系”)。默认情况下,Nginx 使用的是 all 方式。下面是一个例子:

    location /test {

        satisfy all;

 

        deny all;

        access_by_lua 'ngx.exit(ngx.OK)';

 

        echo something important;

    }

这里,我们在 /test 接口中同时配置了 ngx_access 模块和 ngx_lua 模块,这样 access 阶段就由这两个模块一起来做检验工作。其中,语句 deny all 会让 ngx_access 模块的处理程序总是拒绝当前请求,而语句 access_by_lua 'ngx.exit(ngx.OK)' 则总是允许访问。当我们通过 satisfy 指令配置了 all 方式时,就需要 access 阶段的所有模块都通过验证,但不幸的是,这里 ngx_access 模块总是会拒绝访问,所以整个请求就会被拒:

    $ curl localhost:8080/test

    <html>

    <head><title>403 Forbidden</title></head>

    <body bgcolor="white">

    <center><h1>403 Forbidden</h1></center>

    <hr><center>nginx</center>

    </body>

    </html>

细心的读者会在 Nginx 错误日志文件中看到类似下面这一行的出错信息:

    [error] 6549\#0: *1 access forbidden by rule

然而,如果我们把上例中的 satisfy all 语句更改为 satisfy any,

    location /test {

        satisfy any;

 

        deny all;

        access_by_lua 'ngx.exit(ngx.OK)';

 

        echo something important;

    }

结果则会完全不同:

    $ curl localhost:8080/test

    something important

即请求反而最终通过了验证。这是因为在 any 方式下,access 阶段只要有一个模块通过了验证,就会认为请求整体通过了验证,而在上例中,ngx_lua 模块的 access_by_lua 语句总是会通过验证的。

 

    在配置了 satisfy any 的情况下,只有当 access 阶段的所有模块的处理程序都拒绝访问时,整个请求才会被拒,例如:

    location /test {

        satisfy any;

 

        deny all;

        access_by_lua 'ngx.exit(ngx.HTTP_FORBIDDEN)';

 

        echo something important;

    }

此时访问 /test 接口才会得到 403 Forbidden 错误页。这里,post-access 阶段参与了 access 阶段各模块处理程序的“或关系”的实现。

 

    值得一提的是,上面这几个的例子需要 ngx_lua 0.5.0rc19 或以上版本;之前的版本是不能和 satisfy any 配置语句一起工作的。

分享到:
评论

相关推荐

    Nginx关于Rewrite执行顺序详解.docx

    2. **执行Rewrite规则**:在找到的location块内,按照配置文件中的顺序逐个执行`rewrite`指令。每次重写都会重新检查location匹配,因为新的URL可能与之前的不匹配。 3. **last标志的处理**:如果`rewrite`指令后面...

    nginx配置多个静态资源.docx

    本文将详细介绍nginx配置多个静态资源的知识点,从基本概念到配置实践,涵盖了nginx配置文件的各个组件和指令。 nginx配置文件结构 nginx配置文件主要由以下几个部分组成: * main块:定义nginx服务器的基本设置...

    Nginx完整配置说明

    Nginx完整配置说明 Nginx是当前最流行的Web服务器软件之一,...这个配置文件涵盖了Nginx的基本配置、反向代理、FastCGI等方面的知识点,是一个入门级的配置文件。但是,高级指令和配置项需要通过其他渠道学习和了解。

    Nginx配置文件(nginx.conf)配置详解[定义].pdf

    Nginx配置文件(nginx.conf)配置详解 Nginx配置文件(nginx.conf)是Nginx服务器的核心配置文件,用于定义Nginx服务器的行为和配置。下面是Nginx配置文件的详细配置解释: 用户和组 Nginx配置文件中指定了用户和组,...

    Nginx 配置文件 nginx.conf 详解

    Nginx 配置文件 nginx.conf 详解 Nginx 配置文件 nginx.conf 是 Nginx 服务器的核心配置文件,它控制着 Nginx 服务器的行为和性能。在这个配置文件中,我们可以设置服务器的用户和组、工作进程数、错误日志、进程...

    Nginx配置多个访问路径

    Nginx配置多个service 多个访问路径 找到conf/nginx.conf修改配置文件 #user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid ...

    windows下nginx配置https以及同一个端口监听多个网站即监听多个虚拟主机

    在Windows环境下,配置Nginx以支持HTTPS及在同一端口监听多个网站,即配置多个虚拟主机,是一项常见的网络服务设置任务。Nginx是一个高性能的HTTP和反向代理服务器,以其稳定性、高并发处理能力而受到广泛使用。下面...

    nginx配置步骤详细

    * 虚拟主机配置是 Nginx 的一项重要功能,允许在同一个 IP 地址上运行多个网站。 * 需要根据实际情况进行调整和优化,以提高网站的性能和稳定性。 Nginx 配置需要根据实际情况进行调整和优化,以提高网站的性能和...

    nginx配置 +负载均衡+https协议

    - 对于负载均衡,可以通过在Nginx配置文件中定义多个后端服务器,并使用`proxy_pass`指令来实现。 ```nginx upstream backend { server backend1.example.com; server backend2.example.com; } server { ...

    nginx配置多域名访问以及完整配置

    要统计Nginx的访问数量,可以使用`access_log`指令记录日志,然后通过外部工具如`awstats`或`logrotate`进行分析。例如: ```nginx access_log /var/log/nginx/access.log combined; ``` `combined`是日志格式,...

    Windows平台,Nginx配置文件修改自动加载重启

    这是一个监听配置文件变化并执行相应操作的小程序,这里包含了三个文件:`nginx-conf-watcher.bat`、`nginx-conf-watcher.exe`和`nginx-conf-watcher.js`。`nginx-conf-watcher.bat`是一个批处理文件,用于启动监控...

    notepad++编辑nginx配置文件支持高亮

    描述中提到的方法就是通过导入一个名为"userDefineLang_nginx.xml"的文件,这个文件包含了Nginx配置文件的语法规则,如关键字、注释、字符串等的定义。导入步骤如下: 1. 首先,确保你已经下载了"userDefineLang_...

    centos8 nginx1.20.1 与nginx配置文件

    在这个主题中,我们主要关注如何在CentOS 8操作系统上安装Nginx 1.20.1版本以及配置Nginx以支持HTTPS服务。以下是详细的步骤和相关知识点: 首先,我们需要确保CentOS 8系统已经更新到最新状态,通过运行以下命令:...

    nginx配置.zip

    本教程将详细讲解如何在Linux系统(如CentOS)上配置Nginx,特别是涉及`nginx.conf`主配置文件和`conf.d`目录的用法。 1. **Nginx配置基础** Nginx的配置文件通常位于`/etc/nginx/`目录下,其中`nginx.conf`是主...

    微信小程序https服务nginx配置示例.pdf

    6. 反向代理配置:在nginx配置中,proxy_pass指令用于指定后端的服务器地址,这里指向了本地的8080端口。同时,还通过proxy_set_header指令设置了传递给后端服务器的HTTP头信息,如X-Forwarded-For(客户端IP地址)...

    nginx 配置及优化

    5. **location**块:这是Nginx配置中最细粒度的部分,用于匹配请求的URL并执行相应的操作。 ### 二、Nginx负载均衡 Nginx支持多种负载均衡策略,如轮询、最少连接数、IP哈希等,可以有效地分发客户端请求到后端...

    nginx搭建配置详细说明

    3. Nginx的配置文件详解 3.1. Nginx的主配置文件概述 3.1.1. 认识配置文件 3.1.2. nginx的配置文件结构 3.1.3. nginx的全局配置 3.2. events配置 3.3. http的配置 3.4. nginx重要指令之location 4. nginx中的...

    nginx的各项详细配置-超多注释

    - **try_files**: 按顺序查找文件,找到即返回,未找到则按顺序执行下一条指令。 ### 3. Nginx反向代理 通过`proxy_pass`指令,Nginx可以作为反向代理服务器转发请求到后端应用服务器,实现负载均衡、缓存等功能。...

Global site tag (gtag.js) - Google Analytics