Nginx 配置指令的執行順序(七)

2021-09-06 20:19:49 字數 4187 閱讀 6105

來看乙個ngx_static模組服務磁碟檔案的例子。我們使用下面這個配置片段:

location /

同時在本機的/var/www/目錄下建立兩個檔案,乙個檔案叫做index.html,內容是一行文字this is my home;另乙個檔案叫做hello.html,內容是一行文字hello world. 同時注意這兩個檔案的許可權設定,確保它們都對執行 nginx worker 程序的系統帳戶可讀。

現在來通過 http 協議請求一下這兩個檔案所對應的 uri:

我們看到,先前建立的那兩個磁碟檔案的內容被分別輸出了。

不妨來分析一下這裡發生的事情:location /中沒有使用執行在content階段的模組指令,於是也就沒有模組註冊這個location的「內容處理程式」,處理權便自動落到了在content階段「墊底」的那 3 個靜態資源服務模組。首先執行的 ngx_index 和 ngx_autoindex 模組先後看到當前請求的 uri,/index.html/hello.html,並不以/結尾,於是直接棄權,將處理權轉給了最後執行的ngx_static模組。ngx_static模組根據 root 指令指定的「文件根目錄」(document root),分別將請求 uri/index.html/hello.html對映為檔案系統路徑/var/www/index.html/var/www/hello.html,在確認這兩個檔案存在後,將它們的內容分別作為響應體輸出,並自動設定content-typecontent-length以及last-modified等響應頭。

為了確認ngx_static模組確實執行了,可以啟用 (一) 中介紹過的 nginx 「除錯日誌」,然後再次請求/index.html這個介面。此時,在 nginx 錯誤日誌檔案中可以看到類似下面這一行的除錯資訊:

這一行資訊便是ngx_static模組生成的,其含義是「正在輸出的靜態檔案的描述符是數字8」。當然,具體的檔案描述符編號會經常發生變化,這裡只是我機器的一次典型輸出。值得一提的是,能生成這一行除錯資訊的還有標準模組 ngx_gzip_static ,但它預設是不啟用的,後面會專門介紹到這個模組。

注意上面這個例子中使用的 root 配置指令只起到了宣告「文件根目錄」的作用,並不是它開啟了ngx_static模組。ngx_static模組總是處於開啟狀態,但是否輪得到它執行就要看content階段先於它執行的那些模組是否「棄權」了。為了進一步確認這一點,來看下面這個空白location的定義:

location /

因為沒有配置 root 指令,所以在訪問這個介面時,nginx 會自動計算出乙個預設的「文件根目錄」。該預設值是取所謂的「配置字首」(configure prefix)路徑下的html/子目錄。舉乙個例子,假設「配置字首」是/foo/bah/,則預設的「文件根目錄」便是/foo/bar/html/.

那麼「配置字首」是由什麼來決定的呢?預設情況下,就是 nginx 安裝時的根目錄(或者說 nginx 構造時傳遞給./configure指令碼的--prefix選項的路徑值)。如果 nginx 安裝到了/usr/local/nginx/下,則「配置字首」便是/usr/local/nginx/,同時預設的「文件根目錄」便是/usr/local/nginx/html/. 不過,我們也可以在啟動 nginx 的時候,通過--prefix命令列選項臨時指定自己的「配置字首」路徑。假設我們啟動 nginx 時使用的命令是

nginx -p /home/agentzh/test/

則對於該伺服器例項,其「配置字首」便是/home/agentzh/test/,而預設的「文件根目錄」便是/home/agentzh/test/html/. 「配置字首」不僅會決定預設的「文件根目錄」,還決定著 nginx 配置檔案中許多相對路徑值如何解釋為絕對路徑,後面我們還會看到許多需要引用到「配置字首」的例子。

獲取當前「文件根目錄」的路徑有乙個非常簡便的方法,那就是請求乙個肯定不存在的檔案所對應的資源名,例如:

我們會很自然地得到404錯誤頁。此時再看 nginx 錯誤日誌檔案,應該會看到類似下面這一行錯誤訊息:

[error] 9364#0: *1 open() "/home/agentzh/test/html/blah-blah.txt" failed (2: no such file or directory)

這條錯誤訊息是ngx_static模組列印出來的,因為它並不能在檔案系統的對應路徑上找到名為blah-blah.txt的檔案。因為這條錯誤資訊中包含有ngx_static試圖開啟的檔案的絕對路徑,所以從這個路徑不難看出,當前的「文件根目錄」是/home/agentzh/test/html/.

很多初學者會想當然地把404錯誤理解為某個location不存在,其實上面這個例子表明,即使location存在並成功匹配,也是可能返回404錯誤頁的。因為決定著404錯誤頁的是抽象的「資源」是否存在,而非某個具體的location是否存在。

初學者常犯的乙個錯誤是忘記配置content階段的模組指令,而他們自己其實並不期望使用content階段預設執行的靜態資源服務,例如:

location /auth

顯然,這個/auth介面只定義了access階段的配置指令,即 access_by_lua,並未定義任何content階段的配置指令。於是當我們請求/auth介面時,在access階段的 lua **會如期執行,然後content階段的那些靜態檔案服務會緊接著自動發生作用,直至ngx_static模組去檔案系統上找名為auth的檔案。而經常地,404錯誤頁會丟擲,除非運氣太好,在對應路徑上確實存在乙個叫做auth的檔案。所以,一條經驗是,當遇到意外的404錯誤並且又不涉及靜態檔案服務時,應當首先檢查是否在對應的location配置塊中恰當地配置了content階段的模組指令,例如 content_by_lua、 echo 以及 proxy_pass 之類。當然,nginx 的error.log檔案一般總是會提供各種意外問題的答案,例如對於上面這個例子,我的error.log中有下面這條錯誤資訊:

[error] 9364#0: *1 open() "/home/agentzh/test/html/auth" failed (2: no such file or directory)

Nginx 配置指令的執行順序(八)

前面我們詳細討論了rewrite access和content這三個最為常見的 nginx 請求處理階段,在此過程中,也順便介紹了執行在這三個階段的眾多 nginx 模組及其配置指令。同時可以看到,請求處理階段的劃分直接影響到了配置指令的執行順序,熟悉這些階段對於正確配置不同的 nginx 模組並實...

Nginx 配置指令的執行順序(八)

前面我們詳細討論了rewrite access和content這三個最為常見的 nginx 請求處理階段,在此過程中,也順便介紹了執行在這三個階段的眾多 nginx 模組及其配置指令。同時可以看到,請求處理階段的劃分直接影響到了配置指令的執行順序,熟悉這些階段對於正確配置不同的 nginx 模組並實...

Nginx 配置指令的執行順序(十)

執行在post rewrite階段之後的是所謂的preaccess階段。該階段在access階段之前執行,故名preaccess.標準模組 ngx limit req 和 ngx limit zone 就執行在此階段,前者可以控制請求的訪問頻度,而後者可以限制訪問的併發度。這裡我們僅僅和它們打個照面...