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

Nginx 配置指令的执行顺序(五)content & 输出过滤器 (转载)

 
阅读更多

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

 

Nginx 的 content 阶段是所有请求处理阶段中最为重要的一个,因为运行在这个阶段的配置指令一般都肩负着生成“内容”(content)并输出 HTTP 响应的使命。正因为其重要性,这个阶段的配置指令也异常丰富,例如前面我们一直在示例中广泛使用的 echo 指令,在 Nginx 变量漫谈(二) 中接触到的 echo_exec 指令, Nginx 变量漫谈(三) 中接触到的 proxy_pass 指令,Nginx 变量漫谈(五) 中介绍过的 echo_location 指令,以及 Nginx 变量漫谈(七) 中介绍过的 content_by_lua 指令,都运行在这个阶段。

 

    content 阶段属于一个比较靠后的处理阶段,运行在先前介绍过的 rewrite 和 access 这两个阶段之后。当和 rewrite、access 阶段的指令一起使用时,这个阶段的指令总是最后运行,例如:

    location /test {

        # rewrite phase

        set $age 1;

        rewrite_by_lua "ngx.var.age = ngx.var.age + 1";

 

        # access phase

        deny 10.32.168.49;

        access_by_lua "ngx.var.age = ngx.var.age * 3";

 

        # content phase

        echo "age = $age";

    }

这个例子中各个配置指令的执行顺序便是它们的书写顺序。测试结果完全符合预期:

    $ curl 'http://localhost:8080/test'

    age = 6

即使改变它们的书写顺序,也不会影响到执行顺序。其中,set 指令来自 ngx_rewrite 模块,运行于 rewrite 阶段;而 rewrite_by_lua 指令来自 ngx_lua 模块,运行于 rewrite 阶段的末尾;接下来,deny 指令来自 ngx_access 模块,运行于 access 阶段;再下来,access_by_lua 指令同样来自 ngx_lua 模块,运行于 access 阶段的末尾;最后,我们的老朋友 echo 指令则来自 ngx_echo 模块,运行在 content 阶段。

 

    这个例子展示了通过同时使用多个处理阶段的配置指令来实现多个模块协同工作的效果。在这个过程中,Nginx 变量则经常扮演着在指令间乃至模块间传递(小份)数据的角色。这些配置指令的执行顺序,也强烈地受到请求处理阶段的影响。

 

    进一步地,在 rewrite 和 access 这两个阶段,多个模块的配置指令可以同时使用,譬如上例中的 set 指令和 rewrite_by_lua 指令同处 rewrite 阶段,而 deny 指令和 access_by_lua 指令则同处 access 阶段。但不幸的是,这通常不适用于 content 阶段。

 

    绝大多数 Nginx 模块在向 content 阶段注册配置指令时,本质上是在当前的 location 配置块中注册所谓的“内容处理程序”(content handler)。每一个 location 只能有一个“内容处理程序”,因此,当在 location 中同时使用多个模块的 content 阶段指令时,只有其中一个模块能成功注册“内容处理程序”。考虑下面这个有问题的例子:

    ? location /test {

    ?     echo hello;

    ?     content_by_lua 'ngx.say("world")';

    ? }

这里,ngx_echo 模块的 echo 指令和 ngx_lua 模块的 content_by_lua 指令同处 content 阶段,于是只有其中一个模块能注册和运行这个 location 的“内容处理程序”:

    $ curl 'http://localhost:8080/test'

    world

实际运行结果表明,写在后面的 content_by_lua 指令反而胜出了,而 echo 指令则完全没有运行。具体哪一个模块的指令会胜出是不确定的,例如把上例中的 echo 语句和 content_by_lua 语句交换顺序,则输出就会变成 hello,即 ngx_echo 模块胜出。所以我们应当避免在同一个 location 中使用多个模块的 content 阶段指令。

 

    将上例中的 content_by_lua 指令替换为 echo 指令就可以如愿了:

    location /test {

        echo hello;

        echo world;

    }

测试结果证明了这一点:

    $ curl 'http://localhost:8080/test'

    hello

    world

这里使用多条 echo 指令是没问题的,因为它们同属 ngx_echo 模块,而且 ngx_echo 模块规定和实现了它们之间的执行顺序。值得一提的是,并非所有模块的指令都支持在同一个 location 中被使用多次,例如 content_by_lua 就只能使用一次,所以下面这个例子是错误的:

    ? location /test {

    ?     content_by_lua 'ngx.say("hello")';

    ?     content_by_lua 'ngx.say("world")';

    ? }

这个配置在 Nginx 启动时就会报错:

    [emerg] "content_by_lua" directive is duplicate ...

正确的写法应当是:

    location /test {

        content_by_lua 'ngx.say("hello") ngx.say("world")';

    }

即在 content_by_lua 内联的 Lua 代码中调用两次 ngx.say 函数,而不是在当前 location 中使用两次 content_by_lua 指令。

 

    类似地,ngx_proxy 模块的 proxy_pass 指令和 echo 指令也不能同时用在一个 location 中,因为它们也同属 content 阶段。不少 Nginx 新手都会犯类似下面这样的错误:

    ? location /test {

    ?     echo "before...";

    ?     proxy_pass http://127.0.0.1:8080/foo;

    ?     echo "after...";

    ? }

    ?

    ? location /foo {

    ?     echo "contents to be proxied";

    ? }

这个例子表面上是想在 ngx_proxy 模块返回的内容前后,通过 ngx_echo 模块的 echo 指令分别输出字符串 "before..." 和 "after...",但其实只有其中一个模块能在 content 阶段运行。测试结果表明,在这个例子中是 ngx_proxy 模块胜出,而 ngx_echo 模块的 echo 指令根本没有运行:

    $ curl 'http://localhost:8080/test'

    contents to be proxied

要实现这个例子希望达到的效果,需要改用 ngx_echo 模块提供的 echo_before_body 和 echo_after_body 这两条配置指令:

    location /test {

        echo_before_body "before...";

        proxy_pass http://127.0.0.1:8080/foo;

        echo_after_body "after...";

    }

 

    location /foo {

        echo "contents to be proxied";

    }

测试结果表明这一次我们成功了:

    $ curl 'http://localhost:8080/test'

    before...

    contents to be proxied

    after...

配置指令 echo_before_body 和 echo_after_body 之所以可以和其他模块运行在 content 阶段的指令一起工作,是因为它们运行在 Nginx 的“输出过滤器”中。前面我们在 (一) 中分析 echo 指令产生的“调试日志”时已经知道,Nginx 在输出响应体数据时都会调用“输出过滤器”,所以 ngx_echo 模块才有机会在“输出过滤器”中对 ngx_proxy 模块产生的响应体输出进行修改(即在首尾添加新的内容)。值得一提的是,“输出过滤器”并不属于 (一) 中提到的那 11 个请求处理阶段(毕竟许多阶段都可以通过输出响应体数据来调用“输出过滤器”),但这并不妨碍 echo_before_body 和 echo_after_body 指令在文档中标记下面这一行:

    phase: output filter

这一行的意思是,当前配置指令运行在“输出过滤器”这个特殊的阶段。

分享到:
评论

相关推荐

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

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

    Nginx完整配置说明

    Nginx完整配置说明 Nginx是当前最流行的Web服务器软件之一,常用于搭建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配置多个静态资源.docx

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

    centos8 nginx1.20.1 与nginx配置文件

    在`nginx.service`文件中,添加如下内容,确保路径和指令正确: ```ini [Unit] Description=Nginx HTTP Server After=network.target [Service] User=nginx Group=nginx ExecStart=/usr/local/nginx/sbin/nginx ...

    nginx配置步骤详细

    * sendfile 指令指定了 Nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件。 * sendfile 的值可以根据实际情况进行调整,例如普通应用可以设置为 on,磁盘 IO 重负载应用可以设置为 off。 六、keepalive_...

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

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

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

    当Nginx的配置文件被修改后,通常需要手动执行`nginx -s reload`命令来使改动生效,这在频繁调整配置时可能会显得繁琐。本教程将介绍一种方法,使得在Windows环境下,Nginx配置文件修改后能够自动加载并重启,以实现...

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

    在本文中,我们将深入探讨如何配置Nginx以实现多域名访问,同时涵盖访问数量统计、日志请求头配置以及针对手机访问的重定向策略。 ### 1. Nginx多域名配置 在Nginx中,配置多域名主要通过`server`块来实现。每个`...

    Nginx配置http转https以及https访问http静态资源.docx

    五、Nginx配置反向代理 在上面的配置文件中,我们使用了proxy_pass指令来将请求代理到http://www.xxx.com:8080/,以便访问静态资源。同时,我们还使用了proxy_set_header指令来设置代理请求的头信息。 Nginx配置...

    Nginx配置SSL自签名证书的方法

    3. **编辑Nginx配置文件**:找到Nginx的配置文件,通常是`/etc/nginx/nginx.conf`或`/usr/local/nginx/conf/nginx.conf`。添加一个新的`server`块,配置如下: ```nginx server { listen 80; listen 443 ssl; # ...

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

    在标题“notepad++编辑nginx配置文件支持高亮”中,我们关注的是如何在Notepad++中实现对Nginx配置文件的语法高亮显示,这将极大提升开发者的阅读和编写效率。 Nginx是一款高性能的HTTP和反向代理服务器,其配置...

    nginx配置.zip

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

    liunx下nginx 配置&重启

    4. **配置文件的语法**:Nginx的配置文件遵循特定的语法规则,如指令名、参数、大括号等。每个指令后面跟零个或多个参数,参数间用空格分隔。大括号用于包围一组相关指令,形成一个块。 配置完成后,我们需要测试...

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

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

    项目打包运行dist以及nginx配置

    在IT行业中,项目打包运行和Nginx配置是两个关键环节,它们对于应用程序的部署和发布至关重要。这里我们将深入探讨这两个主题。 首先,项目打包运行通常指的是将开发完成的前端或后端应用转换为可部署的形式。对于...

    nginx 配置及优化

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

    windows下 php+nginx配置详解

    安装完Nginx后,我们需要配置它的配置文件`nginx.conf`。这个文件通常位于`nginx`安装目录下的`conf`子目录中。在这个文件中,我们需要定义服务器块来监听HTTP请求,并指定PHP处理器的位置。例如: ```nginx server...

Global site tag (gtag.js) - Google Analytics