HTTP跳转状态码的研究

一直以来都是直接用PHP的header函数输出一个Location标头来实现跳转。很少深究这个跳转具体是怎么实现的,只知道是PHP看到有Location就生成一个302服务器返回状态码。

今天看了HTTP/1.1的协议标准文档,发现除了302 Found外,可以用于跳转的还有301 Moved Permanently、303 See Other以及307 Redirect Temporary。那么这几个状态码有什么不同呢?

顾名思义,301是实现永久跳转的。服务器返回这个状态码,相当于告诉来访者目标地址已经永久转移了,转移后的目标地址用Location标头来描述。由于是永久转移,中间的代理服务器和浏览器都可以缓存这个转移后的目标地址,以后用户再访问的时候,可以不把Request发到服务器上,直接导向目标地址。

302 Found的本意是通知浏览器去请求另一个资源,在HTTP/1.0的定义中,浏览器收到302返回码后,应该用和原请求方法相同的方法来请求目标地址。也就是说,如果浏览器POST到login.php上,而login.php最终返回302,并在Location标头中指定index.php,浏览器就应该再发个POST请求到index.php上。

但是实际情况是,早期版本的浏览器都会用GET方法来发起第二次请求。而早期的Web开发人员也在无数的地方写了大量的302返回码,目的是为了让浏览器跳转并用GET用GET访问。所以最终HTTP/1.1将错就错,加入了303 See Other和307 Redirect Temporary两个状态码。

303 See Other要求用GET方法访问Location中指定的地址。代理服务器或者浏览器可以根据返回标头中的缓存策略对结果加以缓存。现今的大多数浏览器使用处理303的方法来处理302,以保证向前兼容。而反过来,为了兼容早期的浏览器,Web开发人员应该尽量使用302来实现临时重定向。

307 Redirect Temporary就是当年真正的302了,它要求浏览器以完全相同的方法请求Location中指定的地址,而且绝对不可以缓存请求的结果。

现在应该很少见只支持HTTP/1.0的浏览器了,不过网上大量的爬虫程序未必能完整的实现HTTP/1.1,所以平时开发的时候还是多用301和302吧。如果遇到真的需要浏览器重新POST到新地址的情况,用一下307应该也不是问题。

Continue Reading