浅析http状态码301、302、303、307、308区别(转载)
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区别