http的重定向我們經常是張口就來,整個流程也非常簡單,服務端HTTP返回碼是30x,頭裏面的Location字段代表新的URL。如下圖所示:
但重定向也還是有需要深入探討地方,返回碼不僅有我們經常使用301和303還有302 307 308 它們有啥區別呢。可以按照是否緩存和重定向方法,兩個維度去拆分。
緩存(永久重定向) | 不緩存(臨時重定向) | |
轉GET | 301 | 302、303 |
方法保持 | 308 | 307 |
如果是永久重定向那麼瀏覽器客戶端就會緩存此次重定向結果,下次如果有請求則直接從緩存讀取,譬如我們切換域名,將所有老域名的流量轉入新域名,可以使用永久重定向。
如果只是臨時重定向那麼瀏覽器則不會緩存,譬如我們的服務臨時升級,會使用臨時重定向。
方法保持的意思是原請求和重定向的請求是否使用相同的方法,譬如原請求是POST提交一個表單,如果是301重定向的話,重定向的請求會轉爲GET重新提交,如果是308則會保持原來POST請求不變。
RFC協議規範
- 301 Moved Permanently,永久重定向
- 302 Found
- 303 See Other
- 307 Temporary Redirect
- 308 Permanent Redirect 永久重定向
基本結論
- 3XX開頭的HTTP狀態碼都表示重定向的響應。
- 301、308是永久重定向;302、303、307是臨時重定向。
- 301、302是http 1.0的內容,303、307、308是http1.1的內容。
- 301和302本來在http/1.0規範中是不允許重定向時改變請求method的(將POST改爲GET),實際許多瀏覽器實現的時候允許重定向時改變請求method。這就出現了規範和實現不一致的問題
- 302,303,307的出現,都是基於HTTP/1.1兼容HTTP/1.0規範和實現的差異性;
- 303的出現是允許重定向時改變請求method
- 307、308則不允許重定向時改變請求method
- 此外303響應禁止被緩存。
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站竊取了。
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中的實現)。
308
308與301定義一致,唯一的區別在於,308狀態碼不允許瀏覽器將原本爲POST的請求重定向到GET請求上。
小結
在HTTP 1.0規範中,302的規範並沒有被服務器和瀏覽器遵守,即規範和實現出現了二義性,因此在HTTP 1.1中,將302的規範和實現拆分成了303和307。
瀏覽器對307狀態的處理規則和302狀態相同。之所以將值307引入到HTTP/1.1中,是因爲,甚至在最初的消息是POST的情況下,許多瀏覽器依舊錯誤地跟隨302響應中的重定向信息,瀏覽器應該只在接收到303狀態碼時纔跟從POST請求的重定向信息。引入這個新狀態是爲了消除二義性:如果接收到303響應,則繼續進行GET和POST請求的重定向;如果接收到307響應,對於GET請求的重定向,則繼續進行;但對於POST請求的重定向,則不再繼續下去。這是HTTP/1.1新引入的狀態碼。
參考文獻:
淺析http狀態碼301、302、303、307、308區別