Nginx rewrite 轉址 return 301 redirect
網路科技

什麼是 Nginx rewrite?轉址的機制,與 return 301 或 redirect 的差別在哪?

相信稍微有 SEO 和網站概念的讀者,應該都清楚,如果網站網址有改變的話,要用 301 轉址,Google 搜尋上的權重才會整個轉移過去。這也都是舊聞了。

Nginx 除了 return 301 的寫法,另外還有一種 rewrite 的寫法。這篇文章 larry 想聊一聊什麼是 Nginx rewrite,還有跟 return 301 的差別在哪。

什麼是 Nginx rewrite?

首先,什麼是 Nginx rewrite?我們先看 rewrite 的語法:

rewrite 原網址的regex  新網址的url  (flag,可不寫);

官方文件
https://nginx.org/en/docs/http/ngx_http_rewrite_module.html

“The rewrite directives are executed sequentially in order of their appearance in the configuration file. It is possible to terminate further processing of the directives using flags. If a replacement string starts with “http://”, “https://”, or “$scheme”, the processing stops and the redirect is returned to a client.”

意思是如果有寫多筆 rewrite 語法,會依照順序都會執行。如果新網址的url,開頭是 "http://", "https://", "$scheme",則會停止執行下去。

另外,最後一個參數 flag 可以有四個選擇

  • last: 停止接下來的 ngx_http_rewrite_module directives (包含rewrite),並直接跳到符合新網址的 location block。 
  • break: 停止接下來的 ngx_http_rewrite_module directives (包含rewrite),不重新再找。
  • redirect: 新網址開頭不可以是 "http://", "https://", "$scheme",才能用此 flag,並 return 302 轉址。
  • permanent: return 301 轉址。

那 rewrite 的效果到底是什麼?例如

rewrite  /path1  /path2  last;

這樣 /path1 就會顯示 /path2 的內容,而使用者網址列還是 /path1。

但如果 location /path2 中有 try_files,例如

rewrite  /path1  /path2  last;

location /path2 {
    try_files $uri $uri/ /index.php$is_args$args;
}

雖然 last flag 的意思是直接跳到 location /path2,但 $uri 參數還是 path1。也就是即使跳到  location /path2,仍然會顯示 /path1 的內容。換句話說,上例並未真正產生效果。

那如果

location /path1 {
    rewrite /path1 /path2 break;
    rewrite /path1 /path2 last;
    return 200 'my path1';
    add_header Content-Type text/plain;
}

這樣前端 /path1 會 return 自定義的字串 “my path1” 嗎?不會,因為 break 已經跳過第二個 rewrite,而且 return 也是屬於 ngx_http_rewrite_module directive,也跳過。

config 中如果有 try_files,要特別注意

break flag 會跳過後面所有 ngx_http_rewrite_module directives。但注意如果有 try_files,它不屬於 ngx_http_rewrite_module,仍然會執行。

例如

location /path1 {
    rewrite /path1 /path2 break;
    rewrite /path1 /path2 last;
    try_files $uri $uri/ /index.php$is_args$args;
}

這樣前端 /path1 是顯示什麼?仍然顯示原 /path1 的內容。的確第二個 rewrite 被跳過了,但碰到 try_files,仍然執行。

那如果

location /path1 {
    rewrite /path1  /path2  last;
    try_files $uri $uri/ /index.php$is_args$args;
} 

這樣前端 /path1 是顯示什麼?前端 /path1 會顯示 /path2 的內容,因為 last 指令會直接跳到 location /path2。但如果 last 改成 break,則仍顯示原 /path1 的內容。

以上是 lastbreak 的差異。last 似乎可以說是「跳的更乾脆」,甚至底下有 try_files 都不管。break 則是底下有 try_files 的話,仍會執行。

break 的獨特性,如果是寫在 location block,可以避免 Nginx 無窮轉址。相對的,last 因為會重新找符合新網址的 location block,可能會造成無窮迴圈,使用上要小心。

因為 try_files 本身就有重寫網址的意涵,隨著 try_files 的參數往右一直 fallback。所以 rewrite 與 try_files 都有重寫網址的意涵,也可能衝突,使用上要特別小心。

另外還有兩個 flag: redirect、permanent

redirect / permanent 與 last / break 的基本行為邏輯完全不同。

rewrite /path1  /path2  permanent;

不管是 permanent 或是 redirect,使用者網址列顯示的都是 /path2。差別只在 permanent 是先發一個 301 給使用者,通知前端轉到新網址。redirect 則是發 302 給使用者,通知前端轉到新網址。

這裡重複提醒一下,新網址開頭不可以是 "http://", "https://", "$scheme",才能用 redirect。

rewrite 與 return 301 的差別在哪

一般 return 301,可能是這樣寫

return 301  新網址;

我們對比一下 permanent rewrite

rewrite 原網址的regex  新網址的url  permanent;

如果是簡單網址的轉址,都是 301 轉址的機制,效果應該一樣。但是 rewrite 可以用 regex,新網址也可以用 $1$2 組合,變化更多。

換句話說,return 301 是 permanent rewrite 的簡單版。

結論

Nginx rewrite 是很久的東西,但研究起來卻很有內容。走一遍,會很踏實的了解 Nginx config 轉址的機制。

flag last / break 的行為很有趣,但要小心會與 try_files 衝到。

last / break 通常有一個使用情境是「美化網址」。例如將要顯示的網址填在 path1,圖片、影音等多媒體檔案填在 path2。這樣使用者 request path1,就可以顯示 path2 的檔案,而不用輸入真實路徑和副檔名。

last / break 還有一個使用情境是將對外網址,與實際存取的網址分開。例如對外網址是 path1,不要動它,內部實際存取可以是 path2, path3,在 Nginx config 裡面換就好。例如某一條路徑的程式有更新,就切換成 path2 或 path3,不影響客戶端 (他使用的還是 path1)。

permanent / redirect 則是相對單純,就是 301, 302 轉址。

FB公開社團 Larry的午茶時光
加入不需審核,歡迎讀者加入~
我的IG帳號: larry.time.taste。剛剛起步,歡迎大家追蹤~