When a request is processed by nginx, it will go through a series of phases (phases). The following table lists all phases of nginx, and the optional exit methods for each phase. , included modules and corresponding instructions
phase | optional exits | modules / directives | description |
NGX_HTTP_POST_READ_PHASE | HttpRealIpMo dule | read request content phase | |
NGX_HTTP_SERVER_REWRITE_PHASE (server rewrite) | HttpRewriteModule/rewrite | Request address rewrite phase | |
NGX_HTTP_FIND_CONFIG_PHASE (location selection) | HttpCoreModule/location | Configuration lookup phase | |
NGX_HTTP_REWRITE_PHASE Location (location rewrite) | location selection, finalize request |
HttpRewriteModule / rewrite | request address rewrite phase |
NGX_HTTP_POST_REWRITE_PHASE | HttpRewriteModule / rewrite | request address rewrite submission phase | |
NGX_HTTP_PREACCESS_PHASE | degradation, NginxHttpLimitZoneModule / limit_zone, HttpLimitReqModule / limit req, HttpRealIpModule |
Access permission check preparation phase | |
NGX_HTTP_ACCESS_PHASE | finalize request | HttpAccessModule / allow, deny, NginxHttpAuthBasicMo dule/auth_basic | Access permission check phase |
NGX_HTTP_POST_ACCESS_PHASE | Access permission check submission phase | ||
NGX_HTTP_TRY_FILES_PHASE | location selection | HttpCoreModule / try_files | Configuration item try_files processing phase |
NGX_HTTP_CONTENT _PHASE | HttpAutoindexModule / autoindex, HttpCoreModule / Core, HttpDavModule / DAV, HttpEmptyGifModule / EmptyGif, HttpFcgiModule / FastCGI, HttpFlvStreamModul / FLV, HttpGzipStaticModule / gzip_static, HttpIndexModule / index, HttpMemcachedModule / memcached, EmbeddedPerlModule / perl, HttpProxyModule / proxy, HttpProxyModule / random_index, HttpScgiModule / scgi, HttpStubStatusModule / stub_status, HttpUwsgiModule / uwsgi HttpLuaModule / content_by_lua, HttpCoreModule / proxy_pass |
Content generation phase | |
NGX_HTTP_LOG_PHASE | HttpLogModuel / access_log | Log module processing phase |
After reading the request header, it enters the post_read stage. It is located before the uri is rewritten. This stage allows nginx to change the value of the IP address in the request header. , related module HttpRealIpModule.
This phase mainly initializes global variables or server-level rewriting. If the rewrite command is placed in the server, then the server rewrite phase is entered. (See rewrite phase for rewrite instructions)
This phase uses the rewritten uri to find the corresponding location. It is worth noting that this phase may be executed multiple times, because it may There are location-level rewrite directives.
If the rewrite instruction is placed in the location, then it enters the rewrite phase. This stage is the location-level uri rewrite stage, and the rewrite instruction may also be executed multiple times;
Rewrite instructions include the set instruction and rewrite instruction of HttpRewriteModule, the set_by_lua instruction of HttpLuaModule, and the set_unescape_uri instruction of the ngx_set_misc module. In addition, almost all instructions of HttpRewriteModule belong to the rewrite stage.
At this point, let’s think about a question: Since the instructions can be rewritten in this phase without using different modules, can these instructions coexist in the same location? If so, what is their execution order?
Example 1:
Think about the output of the following example?
location /test { set $a 32; set $b 56; set_by_lua $c "return ngx.var.a + ngx.var.b"; set $d "$a + $b = $c"; echo $d; }
When we access http://localhost/test, the output result is 32 + 56 = 88, which should be consistent with our expectations.
But this does not prove that all the instructions of different modules belonging to the same phases must be executed in order when they coexist in a phase. In fact, the third-party modules mentioned above all use special techniques to "inject" their own configuration instructions into the instruction sequence of HttpRewriteModule (they all use the third-party module ngx_devel_kit written by Marcus Clyne). In other words, more conventional rewrite in Nginx Third-party modules that stage registration and run instructions are not so lucky. Although the instructions of these "regular modules" also run in the rewrite stage, their configuration instructions and HttpRewriteModule (and other modules in the same stage) are executed independently. At runtime, the order between the configuration instruction sets of different modules is generally uncertain (strictly speaking, it is generally determined by the loading order of the modules, but there are exceptions). For example, both modules A and B run instructions in the rewrite stage, so either all instructions of module A are executed before executing those instructions of module B, or the other way around, all instructions of module B are executed, and then A is executed. instructions. Unless explicitly stated in the module's documentation, users should generally not write configurations that rely on this indeterminate order. There are also many third-party modules, ngx_array_var And ngx_encrypted_session, which is used to encrypt and decrypt user sessions, can also work seamlessly with the instructions of HttpRewriteModule. The standard HttpRewriteModule is so widely used that third-party modules that can be mixed with its configuration directives are fortunate. Instructions that cannot be mixed with HttpRewriteModule should be noted during actual use. Its output is undefined, which has nothing to do with their order in the configuration file.
Conclusion: If the instructions of different modules with the same scope in the same phase are specially compatible with each other, they will be executed sequentially in the order in which the instructions appear in the configuration file.
Example 2:
Think about the following output What?
location /test { set $value dog; more_set_input_headers "X-Species: $value"; set $value cat; echo "X-Species: $http_x_species"; }
说明:第三方模块 ngx_headers_more 提供了一系列配置指令,用于操纵当前请求的请求头和响应头。其中有一条名叫 more_set_input_headers 的指令可以在 rewrite 阶段改写指定的请求头(或者在请求头不存在时自动创建)。该指令的文档中有这么一行标记 phase: rewrite tail,是说这条指令总是运行在 rewrite 阶段的末尾。显然,写在
more_set_input_headers 指令之后的 set $value cat 语句却先执行了。也就是说属于HttpRewriteModule的set指令先执行完了,才执行ngx_header_more 的set_input_headers指令。
结论:即使运行在同一个请求处理阶段,分属不同模块的配置指令也可能会分开独立运行(除非像 ngx_set_misc 等模块那样针对 ngx_rewrite 模块提供特殊支持)。换句话说,在单个请求处理阶段内部,一般也会以 Nginx 模块为单位进一步地划分出内部子阶段。下面的例子3同例子2:
例子3:
location /test { set $a 1; rewrite_by_lua "ngx.var.a = ngx.var.a + 1"; set $a 56; echo $a; }
说明:HttpLuaModule的rewrite_by_lua 指令也是处在 rewrite tail phase,它也会在rewrite 阶段的末尾执行。因此HttpRewriteModule的所有set执行完后,才执行它。
显然,rewrite_by_lua 指令的行为不同于我们前面在 (二) 中介绍过的 set_by_lua 指令。
小伙伴们可能要问,既然 more_set_input_headers 和 rewrite_by_lua 指令都运行在 rewrite 阶段的末尾,那么它们之间的先后顺序又是怎样的呢?答案是:不一定。我们应当避免写出依赖它们二者间顺序的配置。
结论:作用域在同一个phase的不同modules的指令,如果没有做特殊兼容处理,则它们指令的执行顺序与指令在配置中出现的顺序无关,结果具有不确定性
location级别重写的下一阶段,用来检查上阶段是否有uri重写,并根据结果跳转到合适的阶段;
访问权限控制的前一阶段,该阶段在权限控制阶段之前,一般也用于访问控制,比如限制访问频率,链接数等;相关模块/指令 :NginxHttpLimitZoneModule / limit_zone,
HttpLimitReqModule / limit req, HttpRealIpModule
访问权限控制阶段,比如基于ip黑白名单的权限控制,基于用户名密码的认证控制等;相关模块/指令 HttpAccessModule / allow, deny, NginxHttpAuthBasicModule / auth_basic。 HttpAccessModule提供的 allow 和 deny 配置指令可用于控制哪些 IP 地址可以访问,哪些不可以。HttpAccessModule模块还支持所谓的“CIDR 记法”来表示一个网段,例如 169.200.179.4/24 则表示路由前缀是 169.200.179.0(或者说子网掩码是 255.255.255.0)的网段。
思考下下面两个例子(例子5,例子6)
例子4:
location /hello { allow 127.0.0.1; deny all; echo "hello world"; }
例子5:
location /hello { deny all; allow 127.0.0.1; echo "hello world"; }
例5和例6的区别在于deny all ,和allow 127.0.0.1 这两条指令的顺序不同。但例5中/hello 只允许从本机(IP 地址为保留的 127.0.0.1)访问,而从其他 IP 地址访问都会被拒(返回 403 错误页)。而例6中被配置为任何IP访问都会返回403错误。
原因说明:同属于HttpAccessModule这个模块的多条配置指令之间是按顺序执行的,直到遇到第一条满足条件的指令就不再执行后续的 allow 和 deny 指令。如果首先匹配的指令是 allow,则会继续执行后续其他模块的指令或者跳到后续的处理阶段;而如果首先满足的是 deny 则会立即中止当前整个请求的处理,并立即返回给客户端 403 错误页。
结论:同一个phase的同一个module内的多条指令的执行顺序由这个module自己来定义。
因为 HttpAccessModule的指令运行在 access 阶段,而 access 阶段又处于 rewrite 阶段之后,所以前面我们见到的所有那些在 rewrite 阶段运行的配置指令,都总是在 allow 和 deny 之前执行,而无论它们在配置文件中的书写顺序是怎样的。所以,为了避免阅读配置时的混乱,我们应该总是让指令的书写顺序和它们的实际执行顺序保持一致。
访问权限控制的后一阶段,该阶段根据权限控制阶段的执行结果进行相应处理;
HttpCoreModule的try_files指令的处理阶段,如果没有配置try_files指令,则该阶段被跳过; 该指令作用域: server ,location。
当try_files用于server阶段时一般是初始化作用,用来加载一些文件。
语法: try_files file1,file2,..,fileN-1 ... ,fallback 或者try_files file1,file2,..,fileN = code
用来顺序检查file1,file2,...fileN-1是否存在,如果最后一个字符为/表示这是一个目录。只要找到一个file存在,则进入到content phase,输出内容。如果前N-1个参数代表的file都不存在,此时最后一个参数发挥作用,最后一个参数用于内部跳转,并且只有最后一个参数是用作内部跳转,因此最后一个参数必须存在,否则将会引发一个内部错误。前面的file参数只是设置uri指向,不会引发内部跳转。此外注意: try_files和rewrite不同,rewrite指令会自动保存原请求的参数$args,而try_files最后的fallback参数如果需要带上请求的参数,则需要明确指出,如:
try_files $uri $uri/ /index.php?q=$uri&$args
内容生成阶段,该阶段产生响应,并发送到客户端; 这个阶段相关的模块和指令较多。这里仅拿HttpLuaModule的content_by_lua和HttpEchoModule的echo指令来举个例子再次证明上述谈论到的一个结论。
例子:
location /test { set $a 123; set $b 456; echo $b; content_by_lua ' ngx.say(ngx.var.a) '; }
location /test_echo { content_by_lua ' ngx.say(ngx.var.a) '; set $a 123; set $b 456; }
日志记录阶段,该阶段记录访问日志;
location /test { set $a 11; echo $a; set $a 22; echo $a; }
参考资料:
http://wiki.nginx.org/
http://wiki.nginx.org/Phases
http://blog.sina.com.cn/s/blog_6d579ff40100xpff.html
The above is an introduction to nginx phases, including the relevant content. I hope it will be helpful to friends who are interested in PHP tutorials.