來看乙個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-type
、content-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 就執行在此階段,前者可以控制請求的訪問頻度,而後者可以限制訪問的併發度。這裡我們僅僅和它們打個照面...