HTTP 的重定向和跳轉


楔子

在最開始的時候我們說過,為了實現在互聯網上構建超鏈接文檔系統的設想,蒂姆·伯納斯 - 李發明了萬維網,使用 HTTP 協議傳輸超文本,讓全世界的人都能夠自由地共享信息。超文本里含有超鏈接,可以從一個超文本跳躍到另一個超文本,對線性結構的傳統文檔是一個根本性的變革。能夠使用超鏈接在網絡上任意地跳轉也是萬維網的一個關鍵特性,它把分散在世界各地的文檔連接在一起,形成了復雜的網狀結構,用戶可以在查看時隨意點擊鏈接、轉換頁面。再加上瀏覽器又提供了前進、后退、書簽等輔助功能,讓用戶在文檔間跳轉時更加方便,有了更多的主動性和交互性。

那么,點擊頁面鏈接時的跳轉是怎樣的呢?具體一點,比如在 Nginx 的主頁上點了一下 download 鏈接,會發生什么呢?結合上面的內容,稍微思考一下就能得到答案:瀏覽器首先要解析鏈接文字里的 URI,再用這個 URI 發起一個新的 HTTP 請求,獲取響應報文后就會切換顯示內容,渲染出新 URI 指向的頁面。

這樣的跳轉動作是由瀏覽器的使用者主動發起的,可以稱為 主動跳轉,但還有一類跳轉是由服務器來發起的,瀏覽器使用者無法控制,相對地就可以稱為 被動跳轉,這在 HTTP 協議里有個專門的名詞,叫做 重定向(Redirection)。

重定向的過程

其實之前我們就已經見過重定向了,在介紹 3×× 狀態碼時說過:301 是永久重定向,302 是臨時重定向,瀏覽器收到這兩個狀態碼就會跳轉到新的 URI。也就是說一次重定向實際上發送了兩次 HTTP 請求,但如果不用開發者工具的話,你是完全看不到這個跳轉過程的,也就是說,重定向是用戶無感知的。

如果發生了重定向,那么響應頭中會多出一個 Location 字段,它就是 301/302 重定向跳轉的秘密所在。Location 字段屬於響應字段,必須出現在響應報文里,但只有配合 301/302 狀態碼才有意義,因為它標記了服務器要求重定向的 URI。瀏覽器收到 301/302 報文,會檢查響應頭里有沒有 Location。如果有,就從字段值里提取出 URI,發出新的 HTTP 請求,相當於自動替我們點擊了這個鏈接。

而在 Location 里的 URI 既可以使用絕對 URI,也可以使用相對 URI。所謂絕對 URI,就是完整形式的 URI,包括 scheme、host:port、path 等。所謂相對 URI,就是省略了 scheme 和 host:port,只有 path 和 query 部分,是不完整的,但可以從請求上下文里計算得到,比如這個報文是 https://www.baidu.com 返回的,那么就會將 https://www.baidu.com 和 相對 URI 拼接起來進行跳轉。所以在重定向時如果只是在站內跳轉,你可以放心地使用相對 URI;但如果要跳轉到站外,就必須用絕對 URI。

重定向狀態碼

最常見的重定向狀態碼就是 301 和 302,另外還有幾個不太常見的,例如 303、307、308 等。它們最終的效果都差不多,讓瀏覽器跳轉到新的 URI,但語義上有一些細微的差別,使用的時候要特別注意。

301 俗稱永久重定向(Moved Permanently),意思是原 URI 已經永久性地廢棄,今后的所有請求都必須改用新的 URI。瀏覽器看到 301,就知道原來的 URI 過時了,就會做適當的優化。比如歷史記錄、更新書簽,下次可能就會直接用新的 URI 訪問,省去了再次跳轉的成本。搜索引擎的爬蟲看到 301,也會更新索引庫,不再使用老的 URI。

302俗稱臨時重定向(Moved Temporarily),意思是原 URI 處於臨時維護狀態,新的 URI 是起頂包作用的臨時工。瀏覽器或者爬蟲看到 302,會認為原來的 URI 仍然有效,但暫時不可用,所以只會執行簡單的跳轉頁面,不記錄新的 URI,也不會有其他的多余動作,下次訪問還是用原 URI。

301/302 是最常用的重定向狀態碼,在 3×× 里剩下的幾個還有:

  • 303 See Other:類似 302,但要求重定向后的請求改為 GET 方法,訪問一個結果頁面,避免 POST/PUT 重復操作
  • 307 Temporary Redirect:類似 302,但重定向后請求里的方法和實體不允許變動,含義比 302 更明確
  • 308 Permanent Redirect:類似 307,不允許重定向后的請求變動,但它是 301永久重定向 的含義

不過這三個狀態碼的接受程度較低,有的瀏覽器和服務器可能不支持,開發時應當慎重,測試確認瀏覽器的實際效果后才能使用。

重定向的應用場景

理解了重定向的工作原理和狀態碼的含義,我們就可以在服務器端擁有主動權,控制瀏覽器的行為,不過要怎么利用重定向才好呢?使用重定向跳轉,核心是要理解重定向和 永久 / 臨時 這兩個關鍵詞。先來看什么時候需要重定向:

一個最常見的原因就是 資源不可用,需要用另一個新的 URI 來代替。至於不可用的原因那就很多了,例如域名變更、服務器變更、網站改版、系統維護,這些都會導致原 URI 指向的資源無法訪問,為了避免出現 404,就需要用重定向跳轉到新的 URI,繼續為用戶提供服務。

另一個原因就是 避免重復,讓多個網址都跳轉到一個 URI,增加訪問入口的同時還不會增加額外的工作量。

決定要實行重定向后接下來要考慮的就是永久和臨時的問題了,也就是選擇 301 還是 302。

301 的含義是永久的。如果域名、服務器、網站架構發生了大幅度的改變,比如啟用了新域名、服務器切換到了新機房、網站目錄層次重構,這些都算是永久性的改變。原來的 URI 已經不能用了,必須用 301 永久重定向,通知瀏覽器和搜索引擎更新到新地址,這也是搜索引擎優化(SEO)要考慮的因素之一。

302 的含義是臨時的。原來的 URI 在將來的某個時間點還會恢復正常,常見的應用場景就是系統維護,把網站重定向到一個通知頁面,告訴用戶過一會兒再來訪問。另一種用法就是服務降級,比如在雙十一促銷的時候,把訂單查詢、領積分等不重要的功能入口暫時關閉,保證核心服務能夠正常運行。

重定向的相關問題

重定向的用途很多,掌握了重定向,就能夠在架設網站時獲得更多的靈活性,不過在使用時還需要注意兩個問題。

第一個問題是 性能損耗。很明顯,重定向的機制決定了一個跳轉會有兩次請求 - 響應,比正常的訪問多了一次。雖然 301/302 報文很小,但大量的跳轉對服務器的影響也是不可忽視的。站內重定向還好說,可以長連接復用,站外重定向就要開兩個連接,如果網絡連接質量差,那成本可就高多了,會嚴重影響用戶的體驗。所以重定向應當適度使用,決不能濫用。

第二個問題是 循環跳轉。如果重定向的策略設置欠考慮,可能會出現 A=>B=>C=>A 的無限循環,不停地在這個鏈路里轉圈圈,后果可想而知。所以 HTTP 協議特別規定,瀏覽器必須具有檢測循環跳轉的能力,在發現這種情況時應當停止發送請求並給出錯誤提示。

補充

網頁的入鏈接和出鏈接也是標記網頁重要性的關鍵指標,最著名的就是 Google 發明的 PageRank。

300 Multiple Choices 也是一個特殊的重定向狀態碼,它會返回一個有多個鏈接選項的頁面,由用戶自行選擇要跳轉的鏈接,用的較少。

重定向報文里還可以用 Refresh 字段,實現延時重定向,例如 Refresh: 5; url=xxx 告訴瀏覽器 5 秒鍾后再跳轉。

與跳轉相關的還有一個 Referer 和 Referrer-Policy(前者是個拼寫錯誤,但已經將錯就錯),表示瀏覽器跳轉的來源(即引用地址),可用於統計分析和防盜鏈。比如點擊頁面,如果你在 A 頁面點擊某個鏈接進入了 B 頁面,那么對於 B 頁面而言 Refer 就是 A。之前在做爬蟲的時候,總是被反爬,原因就在於沒有指定 Referer。因為某些頁面需要你點擊才能進去,如果你是直接輸入一個 URI 的話,那么服務器可能就認為你是爬蟲,這個時候通過在 header 中指定 Referer 告訴服務器,我是從 xxx 頁面過來的。

301/302 重定向是由瀏覽器執行的,第一次請求得到 301/302 時,瀏覽器知道這是個重定向,會找到 Location 字段指定的 URI,然后向該 URI 繼續發請求。因此對於服務器而言是外部重定向,相應的也就有內部重定向,內部重定向是在服務器內部跳轉 URI,此時則不會發出 HTTP 請求,從而也就沒有性能損失。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM