nginx-配置指令的执行顺序!
一.引文:
大多数 Nginx 新手都会频繁遇到这样一个困惑,那就是当同一个 location
配置块使用了多个 Nginx 模块的配置指令时,这些指令的执行顺序很可能会跟它们的书写顺序大相径庭。于是许多人选择了“试错法”,然后他们的配置文件就时常被改得一片狼藉。
二. nginx的请求处理流程:
nginx的请求处理阶段共有11个:
-
1. post-read:在 Nginx 读取并解析完请求头(request headers)之后就立即开始运行, 如ngx_http_realip_module
-
2. server-rewrite:当 ngx_rewrite 模块的配置指令直接书写在 server 配置块中时,基本上都是运行在server-rewrite 阶段.
-
3. find-config: 这个阶段并不支持 Nginx 模块注册处理程序,而是由 Nginx 核心来完成当前请求与location 配置块之间的配对工作。换句话说,在此阶段之前,请求并没有与任何 location 配置块相关联。因此,对于运行在 find-config 阶段之前的 post-read 和 server-rewrite 阶段来说,只有server 配置块以及更外层作用域中的配置指令才会起作用。
-
4. rewrite: 由于 Nginx 已经在 find-config 阶段完成了当前请求与 location 的配对,所以从 rewrite 阶段开始,location 配置块中的指令便可以产生作用。前面已经介绍过,当 ngx_rewrite 模块的指令用于 location 块中时,便是运行在这个 rewrite 阶段。ngx_lua 的 rewrite_by_lua 和 set_by_lua(在rewrite 阶段的末尾),
-
5. post-rewrite:这个阶段也像 find-config 阶段那样不接受 Nginx 模块注册处理程序,而是由 Nginx核心完成 rewrite 阶段所要求的“内部跳转”(rewrite)操作(如果 rewrite 阶段有此要求的话)。“为什么不直接在 rewrite 指令执行时立即进行跳转呢?”答案其实很简单,那就是为了在最初匹配的location 块中支持多次反复地改写 (rewrite) URI。
-
6. preaccess: 标准模块 ngx_limit_req 和 ngx_limit_zone 就运行在此阶段,前者可以控制请求的访问频度,而后者可以限制访问的并发度。
-
7. access 多是执行访问控制性质的任务,比如检查用户的访问权限,检查用户的来源 IP 地址是否合法,如标准模块 ngx_access 提供的 allow 和 deny, ngx_access 模块还支持所谓的CIDR 记法来表示一个网段,例如 169.200.179.4/24 . access_by_lua
-
8. post-access: 这个阶段也和 post-rewrite 阶段类似,并不支持 Nginx 模块注册处理程序,而是由Nginx 核心自己完成一些处理工作。post-access 阶段主要用于配合 access 阶段实现标准ngx_http_core 模块提供的配置指令 satisfy 的功能。
-
9. try-files: 这个阶段专门用于实现标准配置指令 try_files 的功能,并不支持 Nginx 模块注册处理程序。
-
10. content :这个阶段是所有请求处理阶段中最为重要的一个,因为这个阶段的配置指令一般都肩负着生成”内容”(content)并输出 HTTP 响应的使使命。正因为其重要性,这个阶段的配置指令也非常多,如:echo ,echo_exec ,proxy_pass ,echo_before_body 和 echo_after_body (这两个属于特殊的 ,运行在“输出过滤器”中phase: output filter )
-
11. log: 日志处理
查看配置指令运行在什么阶段? 大多数指令文档中会有说明(如phase: content)
-
Nginx 各个模块提供的配置指令一般只会注册并运行在其中的某一个处理阶段,为了避免阅读配置时的混乱,我们应该总是让指令的书写顺序和它们的实际执行顺序保持一致
-
在 rewrite 和 access 这两个阶段,多个模块的配置指令可以同时使用,譬如上例中的 set 指令和rewrite_by_lua 指令同处 rewrite 阶段,而 deny 指令和 access_by_lua 指令则同处 access 阶段。但不幸的是,这通常不适用于 content 阶段。 绝大多数 Nginx 模块在向 content 阶段注册配置指令时,本质上是在当前的 location 配置块中注册所谓的”内容处理程序”(content handler)。每一个 location 只能有一个”内容处理程序”,因此,当在 location 中同时使用多个模块的 content 阶段指令时,只有其中一个模块能成功注册”内容处理程序”。 具体哪一个模块的指令会胜出是不确定的.所以我们应当避免在同一个 location 中使用多个模块的 content 阶段指令。
-
并非所有模块的指令都支持在同一个 location 中被使用多次(比如:echo 可以 content_by_lua不行)