搞懂 HTTP 重定向 - 如何優雅地使用 301

最近一段時間,連續遇到了兩次跟重定向相關的問題,本着知己知彼百戰百勝的態度,我決定深刻了解一下,順便跟你們分享一下。html

做爲前端開發,你們對重定向必定不陌生,不就是永久重定向和臨時重定向嘛,誰還不知道呢 😂。前端

那麼你們是否知道永久重定向和臨時重定向的區別呢?若是不當心設置了永久重定向該如何取消呢?如何優雅地使用重定向呢?接下來就讓咱們來一探究竟吧。nginx

URL 重定向,可以將多個 URL 指向同一個頁面,這一技術有着多種用途。在 HTTP 中有一個專門的響應,叫作 HTTP 重定向,也就是全部 3 開頭的響應(這個相信你們都背過)。git

除了 HTTP 重定向,還有其餘方式可以進行重定向,本文也會介紹。github

內容較長,咱們先看一下本文的內容架構:web

  1. HTTP 重定向詳解
  2. 其餘類型的重定向方式
  3. 重定向的使用場景
  4. 如何優雅地使用 301

1. HTTP 重定向

在 HTTP 中,服務器能夠經過返回一個重定向響應來進行重定向。這個重定向響應有一個以 3 開頭的狀態碼 ,而且有一個 Location 頭字段 表示要重定向到的位置。瀏覽器

瀏覽器接收到這個重定向以後,會當即加載 Location 中指定的 URL。一般這一過程耗時極端,用戶基本注意不到這個過程。緩存

重定向過程以下圖所示:服務器

重定向過程
重定向過程

1.1 重定向狀態碼及含義

前面提到,重定向相關的狀態碼都是以 3 開頭的,主要有如下 9 種狀態碼:markdown

狀態碼 狀態短語 狀態含義
300 Multiple Choices 當請求的 URL 對應有多個資源時(如同一個 HTML 的不一樣語言的版本),返回這個代碼時,能夠返回一個可選列表,這樣用戶能夠自行選擇。經過 Location 頭字段能夠自定首選內容。
301 Moved Permanetly 當前請求的資源已被移除時使用,響應的 Location 頭字段會提供資源如今的 URL。直接使用 GET 方法發起新情求。
302 Found 與 301 相似,但客戶端只應該將 Location 返回的 URL 當作臨時資源來使用,未來請求時,仍是用老的 URL。直接使用 GET 方法發起新情求。
303 See Other 用於在 PUT 或者 POST 請求以後進行重定向,這樣在結果頁就不會再次觸發重定向了。
304 Not Modified 資源未修改,表示本地緩存仍然可用。
305 Use Proxy 用來表示必須經過一個代理來訪問資源,代理的位置有 Location 頭字段給出
306 Switch Proxy 在最新版的規範中,306 狀態碼已經再也不被使用。最初是指「後續請求應使用指定的代理」。
307 Temporary Redirect 與 302 相似,可是使用原請求方法發起新情求。
308 Permanent Redirect 與 301 相似,可是使用原請求方法發起新情求。

總共有 9 個與重定向相關的狀態碼,其中 301/302/304 都比較常見,305/306 使用較少,本文不作介紹(其實我也不懂,也沒用過 😂)。這 9 種狀態碼能夠分紅 3 大類,分別是:永久重定向、臨時重定向以及特殊重定向。

1.2 永久重定向類

301 和 308 都屬於永久重定向。永久重定向意味着原始 URL 再也不可用,替換成了一個新的內容。因此搜索引擎、聚合內容閱讀器以及其餘爬蟲識別這兩個狀態碼時,會更新舊 URL 的資源

劃重點:這個就是永久重定向和臨時重定向的區別。

規範中,301 原本不容許改變請求方法,可是已有的瀏覽器廠商都使用了 GET 方法進行新的請求。因此建立了 308 用來處理須要使用非 GET 進行重定向的場景。

1.3 臨時重定向類

302/303/307 都屬於臨時重定向。有時,當原有資源由於一些不可預測的緣由而臨時沒法訪問時,能夠經過臨時重定向的方式將請求轉移到另外一個地方。搜索引擎和爬蟲不該該記住這個臨時的鏈接。

此外,臨時重定向還能夠用來在建立、修改和刪除時展現臨時的進度頁,這裏一般使用 303。

302 和 307 的關係相似於 301 和 308,參見上文。

1.4 特殊重定向類

除此以外,300/304/305/306 能夠歸屬到特殊重定向類。這裏重點說一下 304,304 是 HTTP 緩存中的一個重要內容,表示資源未修改,至關於將資源重定向到本地緩存。

關於 HTTP 緩存的詳細內容,能夠查看這篇文章:瀏覽器緩存策略之掃盲篇

2. 其餘類型的重定向方式

HTTP 是最簡易使用的重定向方式,可是有些時候咱們並不可以操做服務端。好在,除了 HTTP 重定向外,還有兩種方式:經過<meta>進行 HTML 重定向和經過 DOM 的 JS 重定向。

2.1 HTML 重定向

以下代碼所示,咱們能夠經過在<meta>元素上設置http-equiv="Refresh能夠實現頁面的重定向。

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

content屬性須要以數字開頭,表示多少秒以後重定向到指定頁面。一般咱們設置爲 0。

注意,這一方式只適用於 HTML

2.2 JavaScript 重定向

這個你們都用過,使用window.location能夠重定向頁面。這個方法很常見,不過多作介紹。

固然,這一方式只在 JavaScript 的客戶端執行環境有效。

上述所介紹的三種重定向方式中,按照優先級順序以下:HTTP > HTML > JavaScript。這和咱們所知道的文件的請求處理順序一致,不過多解釋。

3. 重定向的使用場景

不一樣類別的重定向有不一樣的使用場景,大體能夠分爲如下幾類:

  • 網站別名:一般狀況下,對於一個資源,咱們只有一個 URL,但有些特殊狀況下,資源會存在多個 URL,這個時候就須要用到重定向。
    • 提升網站的可達率:好比 www.example.comexample.com均可以訪問到指定網站。
    • 遷移到新的站點:由於某些緣由舊站點被廢棄,但仍然但願以前已經存在的鏈接和收藏書籤可以生效,這是可使用重定向。
    • 強制跳轉 HTTPS:當咱們的網站支持 HTTPS 時,一般會強制使用 HTTPS,因此訪問 HTTP 時須要作重定向跳轉。
  • 保證已有連接可用:站點的維護是一個長時間的過程,有時,咱們在進行重構時,會對一些連接或路由進行調整,這時候咱們內部的 URL 能夠修改,可是對於已在被外部引用了的連接卻沒法修改。爲了保證這部分的連接可用,咱們一般須要設置重定向。
  • 對於危險操做進行重定向:相似編輯刪除等危險操做,爲了不用戶刷新時重複觸發危險操做,咱們能夠將其重定向到臨時的進度展現頁,好比使用 303。對於耗時較長的請求也能夠這麼處理。

4. 如何優雅地使用 301

有些時候,咱們對於永久重定向的理解並不夠,在倉促之中使用了 301 永久重定向時就會遇到這樣的一個坑,那就是無論咱們怎麼從新設置,(有些)瀏覽器都仍然使用最開始設置的 301 永久重定向。

這時,咱們的用戶甚至是咱們本身的狀態大概是這樣的:

網站:忍法 - 永久重定向之術 用戶&咱們:我是誰?我在哪?我該怎麼回去?

每每在錯誤配置了 301 以後,咱們須要面臨的問題就是取消最初的 301?

然而,很不幸的是,彷佛並無好的辦法可以快速的清除用戶端已經使用過的錯誤 301 重定向。

若是用戶足夠聰明的話,還可讓用戶按照咱們的說明進行處理。

因此最好的作法是可以搞懂並優雅地使用 301,這樣才能避免這一問題。

下面,咱們先來複現問題,而後再解釋問題。

4.1 準備:使用 Nginx 配置 301 永久重定向

在 Nginx 中,咱們能夠建立一個 server 塊來指定全部內容都進行重定向:

server {
 listen 80;
 server_name example.com;
 return 301 $scheme://www.example.com$request_uri;
}
複製代碼

也能夠經過rewrite指令指定目錄和頁面進行重定向:

rewrite ^/images/(.*)$ https://images.example.com/$1 redirect;
rewrite ^/images/(.*)$ https://images.example.com/$1 permanent;
複製代碼

對於其餘 web 服務器,能夠參考 MDN 或者網上的其餘教程進行配置。

好比我準備了下面這樣一個 nginx.conf 文件。

server {
  listen 80;
  server_name redirect.example.com;
  root /your-path/web-redirect;

  location /original-page {
    # 下面是兩種重定向方式,爲了測試使用,啓用一個便可
    # 永久重定向
    rewrite ^/original-page http://redirect.example.com/301 permanent;
    # # 臨時重定向
    # rewrite ^/original-page http://redirect.example.com/302 redirect;
  }

  location /301 {
    try_files $uri /301.html$is_args$args;
  }

  location /302 {
    try_files $uri /302.html$is_args$args;
  }
}
複製代碼

301.html/302.html 自行準備便可,內容本身能區分出來就行。

如今咱們假設不當心將初始頁面永久重定向到了 301 頁面,如今想取消這一行爲,臨時重定向到 302 頁面。

  1. 先開啓永久重定向的規則,在瀏覽器訪問http://redirect.example.com/original-page,會發現重定向到了 301。
  2. 關閉永久重定向規則,開啓臨時重定向,再次訪問初始頁面,看看是否重定向到了 302 頁面。

至此,咱們會發現,301 以後,瀏覽器會記住第一次的 301,忽略以後的其餘重定向。那這樣究竟是爲何呢?

4.2 瀏覽器會緩存「301」永久重定向

這因此會這樣,這是由於瀏覽器會緩存「301」永久重定向。

經不徹底測試,各瀏覽器的緩存狀況以下:

是否緩存 重啓是否清除 時間改成 1 年後是否失效 5 年後
Chrome 未清除 未失效 未失效
FireFox 未清除 未失效 未失效
Safari 清除 失效 失效
IE --(沒測) -- -- --

能夠看出除了 Safari 重啓/修改時間以後,可以使用新的重定向,Chrome/Firefox 都會無限期的緩存 301 重定向。

在 FireFox 中咱們也能夠簡單驗證下,輸入about:cache,在磁盤緩存中能夠找到相關的緩存項。以下:

FireFox中的301緩存內容
FireFox中的301緩存內容

瀏覽器爲何會緩存 301 重定向呢?其實,HTTP RFC 中規定 301 是一個可緩存的響應,因此瀏覽器會根據響應中的 HTTP 緩存頭進行緩存。若是咱們沒有提供明確的緩存頭,瀏覽器就會默認永久緩存 301 響應,由於 301 是永久重定向的意思。

這裏筆者偷懶沒有測試 IE,可是鑑於有瀏覽器(Chrome/Firefox)會無限期緩存 301 重定向,那麼咱們就須要試着去解決這一問題 —— 如何清除 301 重定向緩存。

4.3 如何清除 301 重定向緩存

心裏戲:不是說無法清除嗎?這怎麼介紹了。我:別急,先看完。

既然是緩存行爲,那麼咱們就能夠經過常規的緩存清理方式來處理,包括但不限於如下幾種方式:

  • 控制檯禁用緩存
  • 清除歷史記錄
  • Network 面板清除緩存

這裏你們能夠自行嘗試如下,若是不行的話,記得多試 1-2 遍就行(至於爲何要多試,我也很奇怪,有的時候就是清兩遍就行了)。

若是你們驗證了上面的幾種清除方式,就會發現確實是行之有效的。那爲何我會說沒有很好地方式去清除呢?

你們細想,當咱們將錯誤的 301 請求發佈到線上環境了,而且影響了數以萬計的用戶時,咱們要怎麼通知並教會用戶按照咱們的方式去清除緩存呢?固然,清除歷史記錄算是最便捷的方式了,若是真的不行遇到了這種狀況,那就通知用戶這麼清除吧 😂。

4.4 優雅地使用 301

爲了不上面須要清除的狀況,最好的作法是優雅地使用 301。

前面解釋瀏覽器爲何會緩存 301 重定向時,已經隱晦地提到了這一方法。

既然瀏覽器認爲這是一個能夠緩存的資源,而且咱們能夠經過緩存頭來控制。那麼在使用 301 時,咱們將其設置爲不緩存就能夠了。好比設置 Cache-Control: no-storeCache-Control: no-cache

location /original-page {
+ add_header Cache-Control no-store;
  # 永久重定向
  rewrite ^/original-page http://redirect.example.com/301 permanent;
  # 臨時重定向
  # rewrite ^/original-page http://redirect.example.com/302 redirect;
}
複製代碼

這樣設置以後,若是咱們再將重定向切換成 302,會發現瀏覽器不會緩存 301 了,新的重定向能夠當即生效了。

總結

以上就是重定向相關的內容。301 使用需謹慎,必定要設緩存頭 😂。


若是你喜歡,歡迎掃碼關注個人公衆號,我會按期陪讀,並分享一些其餘的前端知識喲。

參考連接

  1. 維基百科 - HTTP 狀態碼
  2. MDN - Redirections in HTTP
  3. 瀏覽器將 HTTP 301 緩存多長時間?
  4. 瀏覽器對 301 重定向的緩存
  5. Chromiium - Feature Request: I need a way to clear the 301 redirect cache
相關文章
相關標籤/搜索