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] 網頁由於不可預見的原因暫時不可用。
303 檢視其他 GET方法不變。其他方法更改GET(主體丟失)。 用於在PUTPOST之後重定向,以便重新整理結果頁面不會重新觸發操作。
307 臨時重定向 方法和主體不變 網頁由於不可預見的原因暫時不可用。當站點上提供非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。

您不希望破壞這些連結,因為它們會帶來有價值的使用者並幫助您的搜尋引擎最佳化,因此您會設定從舊 URL 到新 URL 的重定向。

注意:此技術確實適用於內部連結,但請儘量避免使用內部重定向。重定向會產生明顯的效能成本(因為會發生額外的 HTTP 請求)。如果可以透過更正內部連結來避免這種情況,則應更正這些連結。

對不安全請求的臨時響應

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

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

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

對長時間請求的臨時響應

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

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

Apache

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

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

Apache 配置檔案
<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 集合。

Apache 配置檔案
RedirectMatch ^/images/(.*)$ https://images.example.com/$1

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

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

Apache 配置檔案
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 內部伺服器錯誤。如果您在修改伺服器配置後不久遇到此錯誤,則很可能是重定向迴圈。

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

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

…而 Chrome 顯示

此網頁存在重定向迴圈。

在這兩種情況下,使用者都無能為力(除非他們的客戶端出現問題,例如快取或 Cookie 不匹配)。

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