1. 程式人生 > >NGINX重寫規則介紹(一)

NGINX重寫規則介紹(一)

在這篇部落格文章中,我們將討論如何建立NGINX重寫規則(相同的方法適用於NGINX Plus和開源NGINX軟體)。重寫規則會更改客戶端請求中的部分或全部URL,通常用於以下兩種目的之一:

  • 通知客戶他們請求的資源現在位於不同的位置。示例用例是指您的網站的域名已更改,您希望客戶端使用規範的URL格式(帶或不帶www字首),以及何時想要捕獲並糾正域名的常見拼寫錯誤。返回和重寫指令適用於這些目的。
  • 控制NGINX和NGINX Plus中的處理流程,例如在需要動態生成內容時將請求轉發到應用程式伺服器。 try_files指令通常用於此目的。

注意:要了解如何將Apache HTTP伺服器重寫規則轉換為NGINX重寫規則,請參閱我們的配套部落格文章“將Apache重寫規則轉換為NGINX重寫規則”。

我們假設您熟悉HTTP響應程式碼和正則表示式(NGINX和NGINX Plus使用Perl語法)。

比較return,rewrite和try_files指令

通用NGINX重寫的兩個指令是return和rewrite,try_files指令是將請求定向到應用程式伺服器的便捷方式。讓我們回顧一下指令的作用以及它們的區別。

return指令

return指令比兩個通用指令更簡單,因此我們建議在可能的情況下使用它而不是重寫(稍後會詳細說明原因和時間)。將返回包含在指定要重寫的URL的伺服器或位置上下文中,並定義客戶端在將來對資源的請求中使用的更正(重寫)URL。

這是一個將客戶端重定向到新域名的非常簡單的示例:

server {
    listen 80;
    listen 443 ssl;
    server_name www.old-name.com;
    return 301 $scheme://www.new-name.com$request_uri;
}

listen指令表示伺服器塊適用於HTTP和HTTPS流量。 server_name指令匹配域名為www.old-name.com的請求URL。 return指令告訴NGINX停止處理請求並立即將程式碼301(永久移動)和指定的重寫URL傳送到客戶端。重寫的URL使用兩個NGINX變數來捕獲和複製原始請求URL中的值:$ scheme是協議(http或https),$ request_uri是包含引數的完整URI。

對於3xx系列中的程式碼,url引數定義新的(重寫的)URL。

return (301 | 302 | 303 | 307) url;

對於其他程式碼,您可以選擇定義出現在響應正文中的文字字串(HTTP程式碼的標準文字,例如404中未找到,仍包含在標題中)。文字可以包含NGINX變數。

return (1xx | 2xx | 4xx | 5xx) ["text"];

例如,在拒絕沒有有效身份驗證令牌的請求時,此指令可能適用:

return 401 "Access denied because token is expired or invalid";

您還可以使用幾個語法快捷方式,例如省略程式碼(如果是302);請參閱return指令的參考文件。

(在某些情況下,您可能希望返回比在文字字串中實現的更復雜或細微差別的響應。使用error_page指令,您可以為每個HTTP程式碼返回完整的自定義HTML頁面,以及更改響應程式碼或執行重定向。)

因此,返回指令易於使用,並且在重定向滿足兩個條件時是合適的:重寫的URL適用於與伺服器或位置塊匹配的每個請求,並且您可以使用標準NGINX變數構建重寫的URL。 

rewrite指令

但是,如果您需要測試URL之間更復雜的區別,捕獲原始URL中沒有相應NGINX變數的元素,或者更改或新增路徑中的元素,該怎麼辦?在這種情況下,您可以使用重寫指令。

與return指令一樣,您將rewrite指令括在伺服器或位置上下文中,該上下文定義了要重寫的URL。否則,這兩個指令比相似的更加不同,並且重寫指令可能更復雜,無法正確使用。它的語法很簡單:

rewrite regex URL [flag];

但是第一個引數regex意味著NGINX Plus和NGINX只有在匹配指定的正則表示式時才會重寫URL(除了匹配伺服器或位置指令)。附加測試意味著NGINX必須進行更多處理。

第二個區別是重寫指令只能返回程式碼301或302.要返回其他程式碼,您需要在重寫指令後包含一個return指令(請參閱下面的示例)。

最後,重寫指令不一定會像返回那樣停止NGINX對請求的處理,並且它不一定會向客戶端傳送重定向。除非你明確指出(帶有標誌或URL的語法)你希望NGINX停止處理或傳送重定向,否則它會在整個配置中執行,尋找在Rewrite模組中定義的指令(break,if,return,rewrite) ,並設定),並按順序處理它們。如果重寫的URL與Rewrite模組中的後續指令匹配,則NGINX會對重寫的URL執行指示的操作(通常會再次重寫)。

這是事情變得複雜的地方,您需要仔細計劃如何訂購指令以獲得所需的結果。例如,如果原始位置塊和其中的NGINX重寫規則與重寫的URL匹配,則NGINX可以進入迴圈,將重寫一遍又一遍地應用到內建限制10次。要了解所有詳細資訊,請參閱“重寫”模組的文件。如前所述,我們建議您儘可能使用return指令。

這是一個使用rewrite指令的NGINX重寫規則示例。它匹配以字串/ download開頭的URL,然後在路徑後面的某處包含/ media /或/ audio /目錄。它用/ mp3 /替換這些元素,並新增適當的副檔名.mp3或.ra。 $ 1和$ 2變數捕獲不變的路徑元素。例如,/ download / cdn-west / media / file1變為/download/cdn-west/mp3/file1.mp3。如果檔名有副檔名(例如.flv),則表示式將其刪除並將其替換為.mp3。

server {
    # ...
    rewrite ^(/download/.*)/media/(\w+)\.?.*$ $1/mp3/$2.mp3 last;
    rewrite ^(/download/.*)/audio/(\w+)\.?.*$ $1/mp3/$2.ra  last;
    return  403;
    # ...
}

我們在上面提到過,您可以向重寫指令新增標誌以控制處理流程。示例中的最後一個標誌是其中之一:它告訴NGINX跳過當前伺服器或位置塊中的任何後續Rewrite-module指令,並開始搜尋與重寫的URL匹配的新位置。

此示例中的最終返回指令意味著如果URL與rewrite指令不匹配,則將程式碼403返回給客戶端。

try_files指令

與return和rewrite指令一樣,try_files指令放在伺服器或位置塊中。作為引數,它採用一個或多個檔案和目錄的列表以及最終URI: 

try_files file ... uri;

NGINX按順序檢查檔案和目錄是否存在(從根和別名指令的設定構建每個檔案的完整路徑),併為它找到的第一個伺服器提供服務。要指示目錄,請在元素名稱的末尾新增斜槓。如果不存在任何檔案或目錄,NGINX將執行內部重定向到最終元素(uri)定義的URI。

要使try_files指令起作用,還需要定義捕獲內部重定向的位置塊,如以下示例所示。最終元素可以是命名位置,由初始符號(@)表示。

try_files指令通常使用$ uri變數,該變量表示域名後面的URL部分。

在以下示例中,如果客戶端請求的檔案不存在,NGINX將提供預設的GIF檔案。當客戶端請求(例如)http://www.domain.com/images/image1.gif時,NGINX首先在由適用於該位置的根或別名指令指定的本地目錄中查詢image1.gif(未顯示)在摘錄中)。如果image1.gif不存在,NGINX會查詢image1.gif /,如果不存在,則會重定向到/images/default.gif。該值與第二個位置指令完全匹配,因此處理停止並且NGINX為該檔案提供服務並將其標記為快取30秒。

location /images/ {
    try_files $uri $uri/ /images/default.gif;
}

location = /images/default.gif {
    expires 30s;
}

原文連結