??HTTP狀態(tài)碼是服務(wù)器用于告知客戶端一次HTTP請(qǐng)求結(jié)果的描述符金蜀,而以3開頭的3XX狀態(tài)碼表明服務(wù)端不會(huì)就此次請(qǐng)求返回客戶端想要的結(jié)果,客戶端需要執(zhí)行某些特殊的處理來(lái)正確處理請(qǐng)求的畴。其中301
,302
,303
,307
這4個(gè)狀態(tài)碼都表示重定向這個(gè)意思渊抄,即當(dāng)前請(qǐng)求的地址不能正確獲得資源,需要客戶端根據(jù)返回的Location
頭字段去另一個(gè)地址獲取資源丧裁。那么重定向的這四種狀態(tài)碼除了都實(shí)現(xiàn)了重定向功能以及給開發(fā)人員帶來(lái)困惑之外护桦,它們之間的有什么區(qū)別呢?
??根據(jù)標(biāo)準(zhǔn)的定義煎娇,我們可以將這四個(gè)狀態(tài)碼分為兩大陣營(yíng)嘶炭,301
代表的永久重定向陣營(yíng)和302
、303
及307
組成的臨時(shí)重定向陣營(yíng)逊桦。
永久重定向(301) vs 臨時(shí)重定向(302、303抑进、307)
??以兩個(gè)頁(yè)面A和B為例强经,假設(shè)對(duì)A頁(yè)面的請(qǐng)求做了重定向到B頁(yè)面的操作,那么所謂永久重定向寺渗,可以理解為A頁(yè)面的URL所代表的資源永久地被放棄了匿情,以后都由B頁(yè)面代替A,從今往后大家都忘記A吧信殊,只要記住B就可以了炬称;而所謂臨時(shí)重定向,可以理解為A因?yàn)槟承┰驎簳r(shí)不能提供頁(yè)面資源涡拘,大家暫時(shí)先到B頁(yè)面獲取資源玲躯,不過(guò)大家千萬(wàn)別忘了A,因?yàn)檎f(shuō)不定哪天A頁(yè)面又可以正常訪問(wèn)了鳄乏。
用RFC2616里的話怎么說(shuō)呢跷车,對(duì)于301
:
The requested resource has been assigned a new permanent URI and any future references to this resource SHOULD use one of the returned URIs.(已經(jīng)為當(dāng)前請(qǐng)求的資源重新分配了一個(gè)URI,并且將來(lái)在使用這倆個(gè)URI中的任意一個(gè)的時(shí)候這些資源都應(yīng)該被返回)
而對(duì)于302:
The requested resource resides temporarily under a different URI.Since the redirection might be altered on occasion, the client SHOULD continue to use the Request-URI for future requests.(請(qǐng)求的資源暫時(shí)位于不同的URI橱野,但是由于重定向或許會(huì)在將來(lái)被改變朽缴,所以在訪問(wèn)資源時(shí)應(yīng)該繼續(xù)使用之前的那個(gè)URI)
??但是,無(wú)論是301
還是302
(或303
水援、307
)密强,用戶得到的體驗(yàn)是一樣的茅郎,那就是訪問(wèn)A的URL時(shí)看到B的頁(yè)面。那區(qū)分這兩者的意義何在或渤?我們不要忘記系冗,除了用戶(人),Web世界還有兩個(gè)重要參與者劳坑,那就是瀏覽器和搜索引擎毕谴。對(duì)于它們來(lái)說(shuō),對(duì)永久重定向和臨時(shí)重定向的處理是不一樣的距芬。
瀏覽器的處理
??首先來(lái)說(shuō)瀏覽器涝开,對(duì)永久重定向和臨時(shí)重定向的區(qū)別主要體現(xiàn)在對(duì)3XX響應(yīng)的緩存處理上面。RFC2616中對(duì)對(duì)301
關(guān)于緩存的定義:
This response is cacheable unless indicated otherwise.(再無(wú)特殊說(shuō)明的情況下框仔,請(qǐng)求會(huì)被緩存)
而302(或307):
This response is only cacheable if indicated by a Cache-Control or Expires header field.(只有在Cache-Control或者Expires被設(shè)置的情況下舀武,請(qǐng)求才會(huì)被緩存)
303講法上略有不同:
The 303 response MUST NOT be cached, but the response to the second (redirected) request might be cacheable.(303禁止被緩存,但是第二次重定向的請(qǐng)求可以被緩存)
??我們可以發(fā)現(xiàn)离斩,在默認(rèn)的情況下银舱,301
響應(yīng)是被客戶端(通常是瀏覽器)緩存的,而其他重定向響應(yīng)是不被緩存的跛梗。也就是說(shuō)寻馏,當(dāng)對(duì)A的請(qǐng)求被301
重定向之后,這個(gè)重定向響應(yīng)會(huì)被瀏覽器記住核偿,后續(xù)就算A不再重定向了诚欠,瀏覽器根據(jù)緩存的結(jié)果,也會(huì)將請(qǐng)求重定向到B(這里涉及到另一個(gè)問(wèn)題是瀏覽器對(duì)301
響應(yīng)會(huì)緩存多久漾岳,因?yàn)闃?biāo)準(zhǔn)里沒(méi)有明確定義轰绵,所以各個(gè)瀏覽器的處理也是各不相同)。而302
尼荆、303
及307
響應(yīng)左腔,默認(rèn)情況下都不會(huì)被瀏覽器緩存,所以A說(shuō)恢復(fù)就能恢復(fù)捅儒。不過(guò)液样,以上所說(shuō)的都是默認(rèn)情況下,只要我們加上Cache-Control
或Expires
頭野芒,一切都可以改變蓄愁。比如給301
響應(yīng)加上Cache-Control: no-cache
,瀏覽器就不會(huì)記住它狞悲,或者給302
響應(yīng)加上Cache-Control: max-age=2592000
撮抓,瀏覽器就會(huì)將其緩存。
搜索引擎的處理
??搜素引擎對(duì)重定向的處理要復(fù)雜得多摇锋,從理論上講丹拯,搜索引擎遇見永久重定向時(shí)會(huì)刪除對(duì)舊頁(yè)面/舊站點(diǎn)A的索引站超,新頁(yè)面/新站點(diǎn)B會(huì)作為A的替代者或繼承者被收錄到索引中,并且搜索引擎會(huì)轉(zhuǎn)移A的權(quán)重到B身上乖酬;而對(duì)于臨時(shí)重定向死相,搜索引擎會(huì)保留A地址,同時(shí)抓取B的內(nèi)容咬像,A的權(quán)重和排名并不會(huì)轉(zhuǎn)移到B的身上算撮。
??但是搜索引擎在實(shí)際處理時(shí)并沒(méi)有這么簡(jiǎn)單,Google與百度的做法可能也不相同县昂。就301
來(lái)說(shuō)肮柜,搜索引擎可能還得考慮是子域名間的跳轉(zhuǎn),還是不同域名間的跳轉(zhuǎn)倒彰,亦或是同個(gè)域名下的頁(yè)面地址跳轉(zhuǎn)审洞。假設(shè)域名A更換成域名B,對(duì)A的請(qǐng)求做301
重定向待讳,如果A和B有不同的目錄結(jié)構(gòu)芒澜,比如B域名只有一個(gè)首頁(yè),而A域名下路徑/old.html在B域名下并沒(méi)有创淡,這樣B/old.html就會(huì)是404
痴晦,那么B的權(quán)重就會(huì)損失,所以B不一定就能得到A的權(quán)重和排序琳彩。除此之外阅酪,搜索引擎還要考慮A域名的重定向是否值得信任,通常更換域名之后得經(jīng)過(guò)一段時(shí)間B才能獲得跟之前A一樣的權(quán)重汁针。
??重定向在搜索引擎這里還存在一個(gè)叫做PR劫持的問(wèn)題,即空殼網(wǎng)站A利用臨時(shí)重定向(也可能是301
)到B砚尽,讓搜索引擎收錄A施无,同時(shí)記錄B的內(nèi)容,這樣A不費(fèi)吹灰之力就利用了B辛辛苦苦做出的內(nèi)容必孤,從而提高自己的PageRank猾骡。對(duì)于這種情況,搜索引擎有可能會(huì)判斷出A在利用別人的內(nèi)容推銷自己敷搪,進(jìn)而對(duì)A網(wǎng)站做出懲罰兴想。所以,當(dāng)我們?cè)谧鲰?yè)面重定向赡勘,特別是需要考慮到SEO時(shí)嫂便,最好用301
永久重定向,避免影響搜索引擎對(duì)網(wǎng)站動(dòng)機(jī)的判斷闸与。
臨時(shí)重定向之間的區(qū)別
??臨時(shí)重定向會(huì)有302
毙替、303
岸售、307
三種狀態(tài)碼與HTTP協(xié)議推行的歷史有關(guān),在HTTP/1.0
中厂画,只有302
是表示臨時(shí)重定向的凸丸,而在HTTP/1.1
中又添加了303
和307
,它們之間區(qū)別的焦點(diǎn)主要集中在對(duì)非HEAD和非GET方式的HTTP請(qǐng)求進(jìn)行臨時(shí)重定向的處理方式袱院。我們先看一下RFC對(duì)302
在這方面的定義:
If the 302 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.(如果收到302狀態(tài)代碼以響應(yīng)GET或HEAD以外的請(qǐng)求屎慢,則用戶代理不得自動(dòng)重定向請(qǐng)求,除非用戶可以確認(rèn)忽洛,因?yàn)檫@可能會(huì)改變發(fā)出請(qǐng)求的條件)
??也就是說(shuō)在規(guī)范里明確定義了302
重定向在響應(yīng)POST或PUT請(qǐng)求時(shí)腻惠,是不能自動(dòng)進(jìn)行重定向的,需要先得到用戶的確認(rèn)脐瑰⊙叮可是現(xiàn)實(shí)中的情況是多數(shù)的瀏覽器并沒(méi)有遵守這個(gè)規(guī)范,它們的做法是自動(dòng)用GET方法重定向請(qǐng)求目標(biāo)地址苍在。而為了讓這種混亂的情況得到解決绝页,303
和307
被添加進(jìn)來(lái),303在規(guī)范中被定義為如今302
被實(shí)現(xiàn)的情況寂恬,也就是對(duì)于303
響應(yīng)瀏覽器都進(jìn)行GET重定向:
The response to the request can be found under a different URI and SHOULD be retrieved using a GET method on that resource.(在被重定向到其他URI下面時(shí)可以使用GET請(qǐng)求)
??而307
在規(guī)范中被定義為302
規(guī)范所定義的情況续誉,所以根據(jù)RFC2616,我覺(jué)得可以這么說(shuō)初肉,303
和307
是用來(lái)替代302
的酷鸦,它們一個(gè)被定義成302
當(dāng)前的現(xiàn)狀,一個(gè)被定義成302
原本想要實(shí)現(xiàn)的狀態(tài)牙咏,用這兩個(gè)狀態(tài)碼來(lái)明確指定兩種不同的方式臼隔,避免302
規(guī)范與實(shí)現(xiàn)不符的情況。
RFC7231
??但是需要注意的是妄壶,1999年發(fā)布的RFC2616在2014年遭到廢棄摔握,原來(lái)的RFC2616拆分為6個(gè)單獨(dú)的協(xié)議說(shuō)明,其中重定向部分在RFC7231中可以找到最新的定義丁寄,然后你會(huì)發(fā)現(xiàn)氨淌,新規(guī)范并沒(méi)有放棄302,相反伊磺,302
被明確地定義成與它目前的現(xiàn)狀保持一致盛正,即可以用GET方式重定向POST請(qǐng)求,規(guī)范對(duì)302這樣寫道:
Note: For historical reasons, a user agent MAY change the request method from POST to GET for the subsequent request. If this behavior is undesired, the 307 (Temporary Redirect) status code can be used instead.
??RFC7231接受了302
的現(xiàn)狀并且使其成為新的規(guī)范屑埋,307
仍然遵守不能更改重定向方法的規(guī)定豪筝,不過(guò)把需要先得到用戶的確認(rèn)這部分去掉了,而是描述成:
the user agent MUST NOT change the request method if it performs an automatic redirection to that URI.
??那么問(wèn)題來(lái)了,原來(lái)是用303
和307
替換302
壤蚜,現(xiàn)在變成了用新定義的302
和307
替換舊定義的302
即寡,那303
干什么去了呢?在對(duì)303
的最新定義中袜刷,雖然對(duì)其的定義文字比之前增加了很多聪富,但我實(shí)在沒(méi)發(fā)現(xiàn)它跟之前有什么本質(zhì)的區(qū)別,似乎303
反倒成了被拋棄的對(duì)象著蟹。
??那么還有一個(gè)疑問(wèn)是墩蔓,301
對(duì)于非HEAD和非GET方法請(qǐng)求時(shí)的處理是怎么樣的呢?其實(shí)在這方面萧豆,301
跟302
是一樣的狀況奸披,在RFC2616中存在標(biāo)準(zhǔn)與實(shí)現(xiàn)不一致的情況,在RFC7231中事實(shí)現(xiàn)狀被定義成了新的標(biāo)準(zhǔn)涮雷。
總結(jié)
??針對(duì)RFC2616的標(biāo)準(zhǔn)阵面,對(duì)301
、302
洪鸭、303
样刷、307
可以歸納為這個(gè)表格:
狀態(tài)碼 | HTTP版本 | 類別 | 對(duì)POST請(qǐng)求的處理 |
---|---|---|---|
301 | 1.0、1.1 | 永久 | RFC2616:不能用GET重定向览爵;實(shí)現(xiàn):自動(dòng)GET重定向 |
302 | 1.0置鼻、1.1 | 臨時(shí) | RFC2616:不能用GET重定向;實(shí)現(xiàn):自動(dòng)GET重定向 |
303 | 1.1 | 臨時(shí) | 自動(dòng)GET重定向 |
307 | 1.1 | 臨時(shí) | 不能GET重定向 |