リクエストが nginx によって処理されるとき、次の表に nginx のすべてのフェーズと各フェーズのオプションの終了メソッドを示します。含まれるモジュールと対応する命令
フェーズ | オプションの出口 | モジュール/ディレクティブ | 説明 |
NGX_HTTP_POST_READ_PHASE | HttpRealIpMo dule | リクエストコンテンツの読み取りフェーズ | |
NGX_HTTP_SERVER_REWRITE_PHASE (サーバー書き換え) | HttpRewriteModule/rewrite | リクエストアドレス書き換えフェーズ | |
NGX_HTTP_FIND_CONFIG_PHASE (場所の選択) | HttpCoreModule/location | 構成検索フェーズ | |
NGX_HTTP_REWRITE_PHASE 場所 (場所の書き換え) | 場所の選択、 確定request |
HttpRewriteModule / rewrite | リクエストアドレス書き換えフェーズ |
NGX_HTTP_POST_REWRITE_PHASE | HttpRewriteModule / rewrite | リクエストアドレス書き換え送信フェーズ | |
NGX_HTTP_PREACCESS_PHASE | 劣化、NginxHttpLimitZoneModule / limit_zone、 HttpLimitReqModule / 制限req, HttpRealIpModule |
アクセス許可チェック準備フェーズ | |
NGX_HTTP_ACCESS_PHASE | finalize request | HttpAccessModule / allowed、deny、NginxHttpAuthBasicMo dule/auth_basic | アクセス許可チェックフェーズ |
NGX_HTTP_POST_ACCESS_PHASE | アクセス許可送信フェーズの確認 | ||
NGX_HTTP_TRY_FILES_PHASE | 場所の選択 | HttpCoreModule / try_files | 設定項目try_files処理フェーズ |
NGX_HTTP_CONTENT _PHASE | HttpAutoindexModule / autoindex、HttpCoreModule / コア、HttpDavModule / DAV、 HttpEmptyGifModule / EmptyGif 、HttpFcgiModule / FastCGI、HttpFlvStreamModul / FLV、 HttpGzipStaticModule / gzip_static、HttpIndexModule / インデックス、 HttpMemcachedModule / memcached、EmbeddedPerlModule / perl、 HttpProxyModule / プロキシ、 pProxyModule / random_index、 HttpScgiModule / scgi、HttpStubStatusModule / stub_status、 HttpUwsgiModule / uwsgi HttpLuaModule / content_by_lua, HttpCoreModule / proxy_pass |
コンテンツ生成フェーズ | |
NGX_HTTP_LOG_PHASE | HttpLogModuel / access_log | ログモジュール処理フェーズ |
次の例の出力について考えてみてください。
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; }
について考えてみましょう。次の出力は何ですか?
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
上記は、関連コンテンツを含む nginx フェーズの紹介であり、PHP チュートリアルに興味のある友人に役立つことを願っています。