众所周知,我们都知道300-399这一系列的状态码代表的是重定向状态码。重定向状态码要么告知客户端使用替代位置来访问她们所感兴趣的资源,要么就提供一个替代的响应而不是资源的内容。如果资源已被移动,可发送一个重定向状态码和一个可选的Location首部来告知客户端已被移走,以及现在可以在哪里找到它。这样子,浏览器就可以在不打扰用户的情况下,透明地转到新的位置。

那么,接下来,我们从状态码出发,梳理一下3xx状态码(300-307),以及缓存一系列相关的东西。(注:HTTP/1.1版本的内容)

300 Multiple Choices

客户端请求一个实际指向多个资源的URL时会返回这个状态码。

比如说,一个站点提供了中文和英文两个版本,理想情况下,服务器应当向中文用户发送中文版,向英文用户发送英文版。HTTP提供了内容协商方法,允许客户端和服务器作这样的决定。内容协商包含客户端驱动的协商、服务器驱动的协商以及透明协商。

客户端驱动由客户端发起请求,服务器发送可选项的列表,客户端进行选择;服务器驱动是由服务器来检查客户端的请求首部集并决定提供提供哪个版本的页面(q值机制,Vary首部);透明协商是由某个中间设备(通常是缓存代理)代表客户端进行请求协商。

而300 Multiple Choices属于客户端驱动的协商。服务器发送回HTTP/1.1响应时,使用300 Multiple Choices响应代码。客户端浏览器收到这种响应时,可能会弹出对话窗口,让用户选择。

301 Moved Permanently

在请求的URL已被移除时使用。响应的Location首部中应该包含资源现在所处的URL。

301重定向是网页更改网址后对搜索引擎友好的最好方法,只要不是暂时搬移的情况,都建议使用301来做转址。比如说,我们将网页a的地址更改为b,采用301重定向,搜索引擎可以肯定网页a永久性改变网址,搜索引擎就会把网页b当做唯一有效目标,同时,网页a积累的页面权重将被传到网页b。(注:传递权重不同的搜索引擎不一样,Google会传递大部分权重,但不是百分之百权重)

302 Found

与301状态码类似,但是客户端应该使用Location首部给出的URL来临时定位资源,将来的请求仍应使用老的URL。

一般302重定向是在一个网站或网页在短时间内临时移到其它位置的情况下使用,这时候就是做临时性的跳转了。

但是302跟网址“劫持”有着莫大的关系。大部分搜索引擎在大部分情况下,当收到302重定向时,一般只要去抓取目标网址即可。但是有时候搜索引擎(以Google为例)并不能总是抓取目标网址,比如说a网址很短,但是它做了302重定向到b网址,而b网址是一个很长的乱七八糟的URL网址,这时候Google很有可能仍显示网址a,这时候就造成了网址劫持的可能性。如果一个居心叵测的人将一个网址a通过302重定向到你的网址b,而Google搜索结果仍然是A,这种情况就是网址劫持。同时,还容易导致网站被降权,所以尽量不用。

303 See Other

用来告知客户端应该使用另一个URL来获取资源,新的URL位于响应报文的Location首部。

303主要目的是允许POST请求的响应将客户端定位到某个资源上。比如说,在文件上传完成后让客户端自动重定向到一个上传成功的结果页面。

304 Not Modified

如果客户端发送了一个带条件的GET请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器返回304状态码。304响应不包含消息体,因此以消息头后的第一个空行结尾。

在一条HTTP GET请求中,大致是如下的一个过程

http

在查看本地副本是否过期时,通过检查Cache-Control或者Expires首部即可获知。HTTP通过Cache-Control首部和Expires首部向每个文档附加了一个“过期日期”,在缓存文档过期之前,缓存可以以任何频率使用这些副本,而无需与服务器联系。

Expires首部是HTTP/1.0定义的字段,指定的是一个绝对的过期日期。而Cache-Control是HTTP/1.1定义的字段,max-age值定义了文档的最大使用值,是相对时间。因为绝对时间需要依赖于计算机时钟的正确设置,容易存在误差。所以,我们更倾向于使用比较新的Cache-Control首部。当同时存在Expires和Cache-Control:max-age字段时,Cache-Control:max-age字段会覆盖Expires字段。同时存在这两个字段还有一个好处,就是可以兼容HTTP/1.0。

本地缓存过期了并不意味着它和原始服务器上目前处于活跃状态的文档有实际的区别,这时候缓存需要询问原始服务器文档是否发生了改变,跟原始服务器做一次 新鲜度校验

HTTP条件方法可以高效地实现再验证。通过If-Modified-Since或者If-None-Match首部来校验。

If-Modified-Since:Date再验证:If-Modified-Since首部可以和Last-Modified服务器响应首部配合工作。原始服务器会将最后的修改日期附加到所提供的文档上去。

If-None-Match: 实体标签再验证:有些文档可能被被周期性的重写、有些文档可能被修改了但所做修改不重要等等这类情况下,使用最后修改日期进行再验证是不够的,这时候HTTP允许用户对被称为实体标签ETag的“版本标识符”进行比较。

实体标签和最近修改日期都是缓存验证器,如果服务器回送了一个实体标签,HTTP/1.1客户端就必须使用实体标签验证器。如果只返回了一个Last-Modified值,客户端就可以使用If-Modified-Since验证。如果实体标签和最后修改日期都提供了,客户端就应该使用这两种再验证方案,这样HTTP/1.0和HTTP/1.1缓存就都可以正确响应了。如果HTTP/1.1服务器收到的请求既带有If-Modified-Since,又带有ETag条件首部,那么需要这两个条件都满足时,才能返回304 Not Modified响应。

305 Use Proxy

用来说明必须通过一个代理来访问资源,代理的位置由Location首部给出。

客户端是相对某个特定资源来解析这条响应的,不能假定所有请求,甚至所有对特有所请求资源的服务器的请求都通过这个代理进行。如果客户端错误地让代理介入了某条请求,可能会引发破坏性行为,而且会造成安全漏洞。所以,305这个状态码也较少使用。

306 unused

在HTTP1.1废弃掉了,不再使用,并且此状态码被保留。在HTTP1.1以前的版本中,306 Switch Proxy用于表示随后的请求应该使用指定的代理。

307 Temporary Redirect

请求的资源临时从不同的URI响应请求,客户端应该使用Location首部给出的URL来临时定位资源。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。

除非是一个HEAD请求,否则307响应的实体中应当包含指向新的URL的超链接及简短说明。因为部分浏览器不能识别307响应,添加URL超链接以便不能处理307状态码的用户有能力在新URL中发起重定向请求,也就是说,把重定向的页面展示给用户,让用户去点重定向URL链接。

307

我们可以看到Chrome对于hsts列表的域名,采用了307进行重定向。

以上内容讲述了301-307的状态码,对于这些状态码以及一些缓存的首部可能还有一些疑惑,以下简单地列出了几点。

1、从上面的状态码中,你可能注意到302、303和307状态码之间存在一些交叉,那么,它们之间存在哪些细微差别?

303和307是HTTP/1.1新增加的状态码,它们是对HTTP1.0中的302状态码的细化。当HTTP/1.0客户端发起一个POST请求,并在响应中收到302重定向状态码时,它会接受Location首部的重定向URL,并向那个URL发起一个GET请求。透过以上的状态码介绍,我们可以发现HTTP/1.1规范使用303状态码来实现同样的行为。为了避开这个问题,对于HTTP/1.1客户端,用307状态码来代替302状态码进行临时重定向。

在HTTP/1.1中,302理论上是可以被303和307代替掉的,但为了兼容HTTP/1.0,依然还在广泛使用。

2、经常可以看到 Cache-Control: no-cache 这样的首部,那么代表的是不缓存么?

Cache-Control: no-cache 响应实际上是可以存储到本地缓存区中的,只是在与服务器进行新鲜度再验证之前,缓存不能将其提供给客户端使用。

如果需要本地彻底不缓存,需要使用Cache-Control: no-store,表示缓存应该尽快从存储器中删除文档的所有痕迹。