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


前面我們在 (五) 中提到,在一個 location 中使用 content 階段指令時,通常情況下就是對應的 Nginx 模塊注冊該 location 中的“內容處理程序”。那么當一個 location 中未使用任何 content 階段的指令,即沒有模塊注冊“內容處理程序”時,content 階段會發生什么事情呢?誰又來擔負起生成內容和輸出響應的重擔呢?答案就是那些把當前請求的 URI 映射到文件系統的靜態資源服務模塊。當存在“內容處理程序”時,這些靜態資源服務模塊並不會起作用;反之,請求的處理權就會自動落到這些模塊上。

 

    Nginx 一般會在 content 階段安排三個這樣的靜態資源服務模塊(除非你的 Nginx 在構造時顯式禁用了這三個模塊中的一個或者多個,又或者啟用了這種類型的其他模塊)。按照它們在 content 階段的運行順序,依次是 ngx_index 模塊,ngx_autoindex 模塊,以及 ngx_static 模塊。下面就來逐一介紹一下這三個模塊。

 

    ngx_index 和 ngx_autoindex 模塊都只會作用於那些 URI 以 / 結尾的請求,例如請求 GET /cats/,而對於不以 / 結尾的請求則會直接忽略,同時把處理權移交給 content 階段的下一個模塊。而 ngx_static 模塊則剛好相反,直接忽略那些 URI 以 / 結尾的請求。

 

    ngx_index 模塊主要用於在文件系統目錄中自動查找指定的首頁文件,類似 index.html 和 index.htm 這樣的,例如:

    location / {
        root /var/www/;
        index index.htm index.html;
    }

這樣,當用戶請求 / 地址時,Nginx 就會自動在 root 配置指令指定的文件系統目錄下依次尋找 index.htm 和index.html 這兩個文件。如果 index.htm 文件存在,則直接發起“內部跳轉”到 /index.htm 這個新的地址;而如果 index.htm 文件不存在,則繼續檢查 index.html 是否存在。如果存在,同樣發起“內部跳轉”到/index.html;如果 index.html 文件仍然不存在,則放棄處理權給 content 階段的下一個模塊。

 

    我們前面已經在 Nginx 變量漫談(二) 中提到, echo_exec 指令和 rewrite 指令可以發起“內部跳轉”。這種跳轉會自動修改當前請求的 URI,並且重新匹配與之對應的 location 配置塊,再重新執行rewriteaccesscontent 等處理階段。因為是“內部跳轉”,所以有別於 HTTP 協議中定義的基於 302 和 301 響應的“外部跳轉”,最終用戶的瀏覽器的地址欄也不會發生變化,依然是原來的 URI 位置。而ngx_index 模塊一旦找到了 index 指令中列舉的文件之后,就會發起這樣的“內部跳轉”,仿佛用戶是直接請求的這個文件所對應的 URI 一樣。

 

    為了進一步確認 ngx_index 模塊在找到文件時的“內部跳轉”行為,我們不妨設計下面這個小例子:

    location / {
        root /var/www/;
        index index.html;
    }
 
    location /index.html {
        set $a 32;
        echo "a = $a";
    }

此時我們在本機的 /var/www/ 目錄下創建一個空白的 index.html 文件,並確保該文件的權限設置對於運行 Nginx worker 進程的帳戶可讀。然后我們來請求一下根位置(/):

    $ curl 'http://localhost:8080/'
    a = 32

這里發生了什么?為什么輸出不是 index.html 文件的內容(即空白)?首先對於用戶的原始請求 GET /,Nginx 匹配出 location / 來處理它,然后 content 階段的 ngx_index 模塊在 /var/www/ 下找到了index.html,於是立即發起一個到 /index.html 位置的“內部跳轉”。

 

    到這里,相信大家都不會有問題。接下來有趣的事情發生了!在重新為 /index.html 這個新位置匹配location 配置塊時,location /index.html 的優先級要高於 location /,因為 location 塊按照 URI 前綴來匹配時遵循所謂的“最長子串匹配語義”。這樣,在進入 location /index.html 配置塊之后,又重新開始執行rewrite 、access、以及 content 等階段。最終輸出 a = 32 自然也就在情理之中了。

 

    我們接着研究上面這個例子。如果此時把 /var/www/index.html 文件刪除,再訪問 / 又會發生什么事情呢?答案是返回 403 Forbidden 出錯頁。為什么呢?因為 ngx_index 模塊找不到 index 指令指定的文件(在這里就是 index.html),接着把處理權轉給 content 階段的后續模塊,而后續的模塊也都無法處理這個請求,於是 Nginx 只好放棄,輸出了錯誤頁,並且在 Nginx 錯誤日志中留下了類似這一行信息:

    [error] 28789#0: *1 directory index of "/var/www/" is forbidden

所謂 directory index 便是生成“目錄索引”的意思,典型的方式就是生成一個網頁,上面列舉出 /var/www/目錄下的所有文件和子目錄。而運行在 ngx_index 模塊之后的 ngx_autoindex 模塊就可以用於自動生成這樣的“目錄索引”網頁。我們來把上例修改一下:

    location / {
        root /var/www/;
        index index.html;
        autoindex on;
    }

此時仍然保持文件系統中的 /var/www/index.html 文件不存在。我們再訪問 / 位置時,就會得到一張漂亮的網頁:

    $ curl 'http://localhost:8080/'
    <html>
    <head><title>Index of /</title></head>
    <body bgcolor="white">
    <h1>Index of /</h1><hr><pre><a href="../">../</a>
    <a href="cgi-bin/">cgi-bin/</a>  08-Mar-2010 19:36   -
    <a href="error/">error/</a>      08-Mar-2010 19:36   -
    <a href="htdocs/">htdocs/</a>    05-Apr-2010 03:55   -
    <a href="icons/">icons/</a>      08-Mar-2010 19:36   -
    </pre><hr></body>
    </html>

生成的 HTML 源碼顯示,我本機的 /var/www/ 目錄下還有 cgi-bin/error/htdocs/, 以及 icons/ 這幾個子目錄。在你的系統中嘗試上面的例子,輸出很可能會不太一樣。

 

    值得一提的是,當你的文件系統中存在 /var/www/index.html 時,優先運行的 ngx_index 模塊就會發起“內部跳轉”,根本輪不到 ngx_autoindex 執行。感興趣的讀者可以自己測試一下。

 

    在 content 階段默認“墊底”的最后一個模塊便是極為常用的 ngx_static 模塊。這個模塊主要實現服務靜態文件的功能。比方說,一個網站的靜態資源,包括靜態 .html 文件、靜態 .css 文件、靜態 .js 文件、以及靜態圖片文件等等,全部可以通過這個模塊對外服務。前面介紹的 ngx_index 模塊雖然可以在指定的首頁文件存在時發起“內部跳轉”,但真正把相應的首頁文件服務出去(即把該文件的內容作為響應體數據輸出,並設置相應的響應頭),還是得靠這個 ngx_static 模塊來完成。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM