Nginx的指令的執行順序:
一、post-read
ngx_realip模塊的set_real_ip_from和real_ip_header指令(在server里面配置的)
二、server-rewrite
subrequest子請求從這個階段開始執行。
ngx_rewrite模塊的set指令和rewrite指令(前提在server里面配置時)
server { listen 8080; rewrite ^/foo /bar; location /foo { echo foo; } location /bar { echo bar; } }
三、find-config(不接受模塊注冊處理程序)
進行location的配對
四、rewrite
ngx_rewrite模塊的set指令和rewrite指令(前提在location里面配置時)
ngx_set_misc模塊的set_unescape_uri指令
ngx_lua模塊的set_by_lua指令(set_by_lua 指令確實也可以和 set 這樣的 ngx_rewrite 模塊提供的指令混合在一起工作)
rewrite tail:
ngx_headers_more模塊的more_set_input_headers指令
ngx_lua模塊的rewrite_by_lua指令
五、post-rewrite(不接受模塊注冊處理程序)
實現在rewrite階段的內部跳轉
“內部跳轉”本質上其實就是把當前的請求處理階段強行倒退到 find-config 階段,以便重新進行請求URI 與 location 配置塊的配對
rewrite階段的rewrite指令
location /foo { rewrite ^ /bar; rewrite ^ /baz; echo foo; }
兩個rewrite語句都會執行,但只有最后一個才會起作用。因為rewrite指令在rewrite階段執行,但是真正的內部跳轉確是在post-rewrite階段
六、preaccess
ngx_realip模塊的set_real_ip_from和real_ip_header指令(在location里面配置的)
七、access
ngx_access模塊的allow指令和deny指令(多個指令會按順序進行執行)
如果首先匹配的指令是 allow,則會繼續執行后續其他模塊的指令或者跳到后續的處理階段;而如果首先滿足的是 deny 則會立即中止當前整個請求的處理,並立即返回 403 錯誤頁。
access tail:
ngx_lua模塊的access_by_lua指令
tips:指令中return表示該指令就是,繼續執行后續的指令。
tips:ngx_lua模塊的ngx.exit(403)函數,直接結束整個請求處理過程,返回403頁面。
八、post-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; }
比如上面這個就是在access階段的ngx_access模塊的程序和ngx_lua模塊的關系是與的關系,兩個都通過才可以。由於deny all,所以就都返回403了。
deny all和access_by_lua 'ngx.exit(ngx.HTTP_FORBIDDEN)';效果一樣。
九、try-files(不接受模塊注冊處理程序)
配置指令try_files
try_files 指令接受兩個以上任意數量的參數,每個參數都指定了一個 URI. 這里假設配置了 N 個參數,則 Nginx 會在 try-files 階段,依次把前 N-1 個參數映射為文件系統上的對象(文件或者目錄),然后檢查這些對象是否存在。一旦 Nginx 發現某個文件系統對象存在,就會在 try-files 階段把當前請求的 URI 改寫為該對象所對應的參數 URI(但不會包含末尾的斜杠字符,也不會發生 “內部跳轉”),然后執行下一個階段。如果前 N-1 個參數所對應的文件系統對象都不存在,try-files 階段就會立即發起“內部跳轉”到最后一個參數(即第 N 個參數)所指定的 URI.
root /var/www/; location /test { try_files /foo /bar/ /baz; echo "uri: $uri"; } location /foo { echo foo; } location /bar/ {
echo bar;
}
location /baz {
echo baz;
}
curl localhost:8000/test
baz
假設現在 /var/www/ 路徑下是空的,則第一個參數 /foo 映射成的文件 /var/www/foo 是不存在的;同樣,對於第二個參數/bar/ 所映射成的目錄 /var/www/bar/ 也是不存在的。於是此時 Nginx 會在 try-files 階段發起到最后一個參數所指定的 URI(即 /baz)的“內部
跳轉”。當/bar/目錄存在時,URI會被改寫成/bar,末尾的'/'會被去掉。
當然,除了無條件地發起“內部跳轉”之外, try_files 指令還支持直接返回指定狀態碼的HTTP 錯誤頁,例如:try_files /foo /bar/ =404;
十、content階段:
這個階段的這么多的指令只能有一種勝出。每一個location只能有一個內容處理程序。
執行的順序是:如果1里面有就從里面選擇一個執行,如果1里面沒有就讓2執行,如果2沒有或者處理不了就讓3執行,如果3沒有或者處理不了就讓4執行。
1、ngx_echo模塊的echo指令、echo_exec指令、echo_location指令
ngx_proxy模塊的proxy_pass指令
ngx_lua模塊的content_by_lua指令
用一種指令有的可以寫幾次,比如echo。
location /test {
echo hello;
echo world;
}
ngx_lua模塊的ngx.say函數和ngx_echo模塊的echo函數是一樣的
location /test { content_by_lua 'ngx.say("hello") ngx.say("world")'; }
tips:當“文檔根目錄”是 /var/www/ 的時候,請求 URI /foo/bar 會被映射為文件 /var/www/foo/bar,而請求 URI /foo/baz/ 則會被映射為目錄/var/www/foo/baz/. 注意這里是如何通過 URI 末尾的斜杠字符是否存在來區分“目錄”和“文件”的。(這個是對於2、3、4來說的)
2、ngx_index模塊的index指令:(會找root目錄拼接uri目錄下的文件是否存在)
處理以'/'結尾的請求
location / { root /var/www/; index index.htm index.html; }
當用戶請求'/'地址時,Nginx會自動在/var/www/index.htm目錄下尋找這個文件,如果找到,則直接發起內部跳轉到新的'/index.html'這個新的地址,如果不存在,則繼續找/var/www/index.html這個文件,如果找得到,則直接發起內部跳轉到'/index.html'這個地址,如果不存在,就交給后續的模塊進行處理,如果都處理不了,就報403的錯誤。
3、ngx_autoindex模塊的autoindex指令:(會找root目錄拼接uri目錄下的文件是否存在)
處理以'/'結尾的請求
自動生成目錄索引頁
location / { root /var/www/; index index.html; autoindex on; }
當請求到來時,當/var/www/index.html的頁面不存在時,會顯示/var/www/下的文件目錄列表;當index.html的存在時,會優先執行ngx_index模塊的index指令,直接發生內部跳轉。
4、ngx_static模塊的靜態資源指令:(會找root目錄拼接uri目錄下的文件是否存在)
處理不以'/'結尾的網頁
專門用來處理和輸出靜態資源內容的
location / {
root /var/www/
}
因為沒有配置 root 指令,所以在訪問這個接口時,Nginx 會自動計算出一個缺省的“文檔根目錄”。該缺省值是取所謂的“配置前綴 prefix路徑下的 html/ 子目錄。舉一個例子,假設配置前綴是 /foo/bar/,則缺省的“文檔根目錄”便是 /foo/bar/html/。
當靜態資源找不到時會出現404錯誤。404是指靜態資源找不到,而並非location找不到。當然如果location找不到也是404。
十一、log
參考知識點:
1、內部跳轉:(瀏覽器地址不發生變化)
ngx_index模塊的index指令
echo模塊的echo_exec指令
ngx_rewrite模塊的rewrite指令
try_files的最后一跳
2、HTTP的頭部參數的獲取
$http_XXX 內建變量在讀取時會返回當前請求中名為 XXX 的請求頭
需要注意的是, $http_XXX 變量在匹配請求頭時會自動對請求頭的名字進行歸一化,即將名字的大寫字母轉換為小寫字母,同時把間隔符(-)替換為下划線(_)
3、輸出過濾器
ngx_echo模塊的echo_before_body和echo_after_body
Nginx 在輸出響應體數據時都會調用“輸出過濾器”,不屬於某個階段,只要有輸出響應,就會調用輸出過濾器。
4、外部跳轉
302 和 301 響應的“外部跳轉”,瀏覽器地址發生變化。