HTTP 中的重定向

URL 重定向,也稱為URL 轉發,是一種為頁面、表單、整個網站或 Web 應用程式提供多個 URL 地址的技術。HTTP 為此操作提供了一種特殊的響應,稱為 HTTP 重定向

重定向可實現眾多目標

  • 網站維護或停機期間的臨時重定向
  • 更改網站 URL 後,為保留現有連結/書籤的永久重定向;上傳檔案時的進度頁面等。

原理

在 HTTP 中,重定向是由伺服器向請求傳送特殊的重定向響應觸發的。重定向響應具有以 3 開頭的狀態碼和包含要重定向到的 URL 的 Location 標頭。

當瀏覽器收到重定向時,它們會立即載入 Location 標頭中提供的新 URL。除了額外的往返帶來的少量效能損失外,使用者很少會注意到重定向。

A request made from client to server. The server responds with "301:moved permanently" and the new URL for the resource. The client makes a GET request for the new URL which is returned by the server, with a 200 OK response.

重定向有多種型別,分為三類

  1. 永久重定向
  2. 臨時重定向
  3. 特殊重定向

永久重定向

這些重定向旨在永久有效。它們意味著原始 URL 不應再使用,並被新 URL 替換。搜尋引擎機器人、RSS 閱讀器和其他爬蟲會更新資源的原始 URL。

程式碼 文字 方法處理 典型用例
301 永久移動 GET 方法不變。其他方法可能會或可能不會更改為 GET。[1] 網站重組。
308 永久重定向 方法和正文不變。 網站重組,包含非 GET 連結/操作。

[1] 規範無意允許方法更改,但現有使用者代理確實會更改其方法。308 的建立是為了消除使用非 GET 方法時行為的模糊性。

臨時重定向

有時無法從其規範位置訪問請求的資源,但可以從其他位置訪問。在這種情況下,可以使用臨時重定向。

搜尋引擎機器人和其他爬蟲不會記住新的臨時 URL。臨時重定向也用於建立、更新或刪除資源時,以顯示臨時進度頁面。

程式碼 文字 方法處理 典型用例
302 已找到 GET 方法不變。其他方法可能會或可能不會更改為 GET。[2] Web 頁面因不可預見的原因暫時不可用。
303 檢視其他 GET 方法不變。其他方法更改GET(正文丟失)。 PUTPOST 後用於重定向,這樣重新整理結果頁面就不會重新觸發操作。
307 臨時重定向 方法和正文不變 Web 頁面因不可預見的原因暫時不可用。當網站上存在非 GET 操作時,比 302 更好。

[2] 規範無意允許方法更改,但現有使用者代理確實會更改其方法。307 的建立是為了消除使用非 GET 方法時行為的模糊性。

特殊重定向

304(未修改)將頁面重定向到本地快取的副本(已過期),而 300(多項選擇)是手動重定向:瀏覽器以網頁形式顯示的正文列出了可能的重定向,使用者點選其中一個進行選擇。

程式碼 文字 典型用例
300 多項選擇 不多:選項在正文中的 HTML 頁面中列出。鼓勵將機器可讀的選項作為帶有 rel=alternateLink 標頭髮送。
304 未修改 針對重新驗證的條件請求傳送。指示快取的響應仍然有效且可以使用。

指定重定向的替代方式

HTTP 重定向不是定義重定向的唯一方式。還有另外兩種方式

  1. 使用 <meta> 元素的 HTML 重定向
  2. 透過 DOM 的 JavaScript 重定向

HTML 重定向

HTTP 重定向是建立重定向的最佳方式,但有時您無法控制伺服器。在這種情況下,請嘗試在頁面的 <head> 中使用 <meta> 元素,並將其 http-equiv 屬性設定為 Refresh。顯示頁面時,瀏覽器將轉到指示的 URL。

html
<head>
  <meta http-equiv="Refresh" content="0; URL=https://example.com/" />
</head>

content 屬性應以一個數字開頭,指示瀏覽器在重定向到給定 URL 之前應等待多少秒。為了符合輔助功能要求,始終將其設定為 0

顯然,此方法僅適用於 HTML,不能用於影像或其他型別的內容。

JavaScript 重定向

JavaScript 中的重定向透過將 URL 字串設定為 window.location 屬性來執行,從而載入新頁面

js
window.location = "https://example.com/";

與 HTML 重定向一樣,這不能對所有資源都有效,而且顯然,這隻適用於執行 JavaScript 的客戶端。另一方面,有更多可能性:例如,您可以僅在滿足某些條件時觸發重定向。

優先順序

有三種觸發重定向的方式,可以同時使用多種方式。但哪個先應用?

  1. HTTP 重定向總是首先執行——它們甚至在沒有傳輸頁面時就存在了。
  2. 有點令人驚訝的是,JavaScript 重定向在 HTML 重定向之前執行。這是因為 <meta> 重定向發生在頁面完全載入之後,也就是所有指令碼執行之後。
  3. 如果頁面載入之前沒有執行任何 HTTP 重定向或 JavaScript 重定向,則執行 HTML 重定向(<meta>)。
  4. 如果在頁面載入後發生任何 JavaScript 重定向(例如,點選按鈕時),如果頁面尚未被先前的方法重定向,它將最後執行。

如果可能,請使用 HTTP 重定向,不要新增 <meta> 元素重定向。如果有人更改了 HTTP 重定向但忘記更改 HTML 重定向,重定向將不再相同,這可能導致無限迴圈或其他噩夢。

用例

重定向有許多用例,但由於每次重定向都會影響效能,因此應將其使用降至最低。

域名別名

理想情況下,每個資源都有一個位置,因此有一個 URL。但資源有替代名稱的原因

擴大您網站的覆蓋範圍

一個常見的情況是,網站位於 www.example.com,但從 example.com 訪問也應該有效。因此,會設定將 example.com 重定向到 www.example.com。您還可以從您的域名的常見同義詞或常見拼寫錯誤進行重定向。

遷移到新域名

例如,您的公司改名了,但您希望現有連結或書籤仍然可以透過新名稱找到您。

強制 HTTPS

對您網站的 http:// 版本的請求將重定向到您網站的 https:// 版本。

重構網站時,URL 會更改。即使您更新網站連結以匹配新 URL,您也無法控制外部資源使用的 URL。

您不想破壞這些連結,因為它們會帶來有價值的使用者並幫助您的 SEO,因此您會設定從舊 URL 到新 URL 的重定向。

注意:此技術適用於內部連結,但儘量避免內部重定向。重定向會產生顯著的效能成本(因為會發生額外的 HTTP 請求)。如果您可以透過糾正內部連結來避免它,您應該修復這些連結。

對不安全請求的臨時響應

不安全的請求會修改伺服器的狀態,使用者不應無意中重新發送它們。

通常,您不希望使用者重新發送 PUTPOSTDELETE 請求。如果您將此請求的結果作為響應提供,則按重新載入按鈕將重新發送請求(可能在確認訊息之後)。

在這種情況下,伺服器可以針對包含正確資訊的 URL 發回 303(檢視其他)響應。如果按下重新載入按鈕,只會重新顯示該頁面,而不會重播不安全的請求。

對長時間請求的臨時響應

某些請求可能需要在伺服器上花費更多時間,例如計劃稍後處理的 DELETE 請求。在這種情況下,響應是 303(檢視其他)重定向,該重定向連結到一個頁面,指示操作已安排,並最終通知其進度或允許取消它。

在常用伺服器中配置重定向

Apache

重定向可以在伺服器配置檔案或每個目錄的 .htaccess 中設定。

mod_alias 模組具有 RedirectRedirectMatch 指令,預設情況下會設定 302 重定向

apacheconf
<VirtualHost *:443>
  ServerName example.com
  Redirect / https://www.example.com
</VirtualHost>

URL https://example.com/ 將重定向到 https://www.example.com/,其下的任何檔案或目錄也將重定向(https://example.com/some-page 將重定向到 https://www.example.com/some-page

RedirectMatch 作用相同,但接受正則表示式來定義受影響的 URL 集合

apacheconf
RedirectMatch ^/images/(.*)$ https://images.example.com/$1

images/ 目錄中的所有文件都將重定向到不同的域。

如果您不想要臨時重定向,可以使用額外的引數(要使用的 HTTP 狀態碼或 permanent 關鍵字)來設定不同的重定向

apacheconf
Redirect permanent / https://www.example.com
# …acts the same as:
Redirect 301 / https://www.example.com

mod_rewrite 模組也可以建立重定向。它更靈活,但也更復雜一些。

Nginx

在 Nginx 中,您為要重定向的內容建立一個特定的伺服器塊

nginx
server {
  listen 80;
  server_name example.com;
  return 301 $scheme://www.example.com$request_uri;
}

要將重定向應用於目錄或僅某些頁面,請使用 rewrite 指令

nginx
rewrite ^/images/(.*)$ https://images.example.com/$1 redirect;
rewrite ^/images/(.*)$ https://images.example.com/$1 permanent;

IIS

在 IIS 中,您使用 <httpRedirect> 元素來配置重定向。

重定向迴圈

重定向迴圈發生在已跟蹤的重定向之後又出現額外重定向時。換句話說,存在一個永遠不會結束的迴圈,並且永遠找不到頁面。

大多數情況下,這是一個伺服器問題,如果伺服器能夠檢測到它,它會返回 500 Internal Server Error。如果您在修改伺服器配置後不久遇到此類錯誤,則很可能是重定向迴圈。

有時,伺服器不會檢測到它:重定向迴圈可能跨越多個伺服器,每個伺服器都沒有完整的檢視。在這種情況下,瀏覽器會檢測到它並顯示錯誤訊息。Firefox 顯示

Firefox 檢測到伺服器以一種永遠不會終止的方式重定向此地址的請求。

……而 Chrome 顯示

此網頁存在重定向迴圈

在這兩種情況下,使用者都無能為力(除非他們一方發生損壞,例如快取或 Cookie 不匹配)。

避免重定向迴圈很重要,因為它們會完全破壞使用者體驗。

另見