1. 程式人生 > >【HTTP】http重定向301/302/303/307

【HTTP】http重定向301/302/303/307

一、概述

    重定向常常和請求轉發放在一起討論(前者是兩次不相關的請求,後者是一次請求伺服器端轉發),然而本文並不討論兩者的區別,而是HTTP 1.0規範和HTTP 1.1規範中關於重定向的區別,以及實際使用中的情況。

    重定向實際使用是一個響應碼(301或302或303或307)和一個響應頭location,當瀏覽器收到響應的時候check響應碼是3xx,則會取出響應頭中location對應的url(重定向中url的編碼問題,請參看點選開啟連結),然後將該url替換瀏覽器位址列併發起另一次HTTP事務。

    關於301、302、303、307的區別,找不到好的文章,因此打算直擼HTTP 1.0規範和HTTP 1.1規範,結合一些實際的案例和tomcat實現,來說清楚這幾個狀態碼的差異。

1. 百度https重定向

    如下圖所示,原請求訪問的是http://www.baidu.com,然後返回302和location=https://www.baidu.com,從http轉到https。不過關於響應行中302狀態碼的描述存在爭議,在下文中會詳細討論。




2. tomcat重定向原始碼


二、詳細

    http 1.0規範中有2個重定向——301和302,在http 1.1規範中存在4個重定向——301、302、303和307,其中302是值得討論討論的。

1. http 1.0

301

    301狀態碼在HTTP 1.0和HTTP 1.1規範中均代表永久重定向,對於資源請求,原來的url和響應頭中location的url而言,資源應該對應location中的url。對於post請求的重定向,還是需要使用者確認之後才能重定向,並且應該以post方法發出重定向請求。

    關於post請求重定向使用者確認的問題,實際上瀏覽器都沒有實現;而且post請求的重定向應該發起post請求,這裡瀏覽器也並不一定遵守,所以說HTTP規範的實現並未嚴格按照HTTP規範的語義。

    在301中資源對應的路徑修改為location的url,在SEO中並未出現問題,但是在302中就出現了302劫持問題,請往下看。


302

    在http 1.0規範中,302表示臨時重定向,location中的地址不應該被認為是資源路徑,在後續的請求中應該繼續使用原地址。

    規範:原請求是post,則不能自動進行重定向;原請求是get,可以自動重定向;

    實現:瀏覽器和伺服器的實現並沒有嚴格遵守HTTP中302的規範,伺服器不加遵守的返回302,瀏覽器即便原請求是post也會自動重定向,導致規範和實現出現了二義性,由此衍生了一些問題,譬如302劫持,因此在HTTP 1.1中將302的規範細化成了303和307,希望以此來消除二義性。

    補充:302劫持——A站通過重定向到B站的資源xxoo,A站實際上什麼都沒做但是有一個比較友好的域名,web資源xxoo存在B站並由B站提供,但是B站的域名不那麼友好,因此對搜尋引擎而言,可能會儲存A站的地址對應xxoo資源而不是B站,這就意味著B站出了資源版權、頻寬、伺服器的錢,但是使用者通過搜尋引擎搜尋xxoo資源的時候出來的是A站,A站什麼都沒做卻被索搜引擎廣而告之使用者,B站做了一切卻不被使用者知道,價值被A站竊取了。


2. http 1.1

301

    和http 1.0規範中保持一致,注意資源對應的路徑應該是location中返回的url,而不再是原請求地址。

302

    在HTTP 1.1中,實際上302是不再推薦使用的,只是為了相容而作保留。規範中再次重申只有當原請求是GET or HEAD方式的時候才能自動的重定向,為了消除HTTP 1.0中302的二義性,在HTTP 1.1中引入了303和307來細化HTTP 1.0中302的語義。


303

    在HTTP 1.0的時候,302的規範是原請求是post不可以自動重定向,但是伺服器和瀏覽器的實現是執行重定向。

    把HTTP 1.0規範中302的規範和實現拆分開,分別賦予HTTP 1.1中303和307,因此在HTTP 1.1中,303繼承了HTTP 1.0中302的實現(即原請求是post,也允許自動進行重定向,結果是無論原請求是get還是post,都可以自動進行重定向),而307則繼承了HTTP 1.0中302的規範(即如果原請求是post,則不允許進行自動重定向,結果是post不重定向,get可以自動重定向)。


307

    在http 1.1規範中,307為臨時重定向,注意劃紅線的部分,如果重定向307的原請求不是get或者head方法,那麼瀏覽器一定不能自動的進行重定向,即便location有url,也應該忽略。

    也就是307繼承了302在HTTP 1.0中的規範(303繼承了302在HTTP 1.0中的實現)。


3. 小結

    在HTTP 1.0規範中,302的規範並沒有被伺服器和瀏覽器遵守,即規範和實現出現了二義性,因此在HTTP 1.1中,將302的規範和實現拆分成了303和307。


三、結論

    雖然在不同版本的http規範中對重定向賦予了不同的語義,但是因為使用歷史和伺服器實現等原因,在實際中並不一定安全按照http規範實現,因此我個人感覺上述討論只是一個瞭解,在實際寫程式碼中302還是繼續用吧···

參考:

1. 《http 1.0規範》
2. 《http 1.1規範》

附註:

    本文如有錯漏,煩請不吝指正,謝謝!