条件请求有两个用途
条件请求是指浏览器能够询问服务器,是否有最新资源的副本。浏览器会发送些它持有的缓存资源的一些信息,服务器决定是否返回更新的数据或者使用浏览器的副本(也就是资源没更新)。若依然使用浏览器的副本,则响应状态码为304(not modified)。
虽然条件请求也会在网络中发生调用,但是在资源未修改时,其响应体是空的(节省了传输资源给客户端的成本)。服务器能够很快的在不访问资源的情况下决定资源最后修改时间。
若资源在浏览器副本缓存后改变,则会传送内容;否则返回304。
1.1实现过程
为了保证条件请求,应用通过Last-Modified指定资源的最近修改时间,返回给浏览器。
Last-Modified: Mon, 03 Jan 2011 17:45:57 GMT
下次,浏览器请求这个资源时,会询问资源是否自从这个时间修改过,通过If-Modified-Since。
If-Modified-Since: Mon, 03 Jan 2011 17:45:57 GMT
若自从Mon, 03 Jan 2011 17:45:57 GMT时间没有修改过,则返回响应码是304,响应体是空的响应。
1.2图示
ETag(or Entity Tag)是资源版本的标识符。
工作方式类似于Last-Modified,只是ETag值是资源的digest(比如,MD5 hash)。
当Last-Modified时间很难确定时,ETag就很有用了。
2.1实现
//服务器响应头
ETag: "15f0fff99ed5aae4edffdd6496d7131f"
后续,若浏览器带If-None-Match,把上一次请求的资源版本ETag发送给服务器
//客户端请求头
If-None-Match: "15f0fff99ed5aae4edffdd6496d7131f"
与If-Modified-Since类似,若版本一致,则说明服务器版本未修改过,可以使用缓冲,返回状态码304
2.2图示
若要支持断点续传请求,则要在响应头部Access-Ranges:bytes。否则写If-Range无用
If-Range的值是ETag或Last-Modified的值。若一致,则作为范围请求处理,否则返回全部资源
If-Range要和Range共同使用,否则服务器会忽略。
(这样做也是合理的,因为ETag不变,说明资源未变,则直接返回客户端请求的资源即可;若资源改变,请求的部分资源没有了,应该返回所有的新资源)
The If-Range
HTTP request header makes a range request conditional: if the condition is fulfilled, the range request will be issued and the server sends back a 206 Partial Content
answer with the appropriate body. If the condition is not fulfilled, the full resource is sent back, with a 200 OK
status.
Range指定范围,若是合法且If-Range有效,则返回206;若范围不合法,则返回416 Range Not Satifiable error。服务器也可忽略Range返回200整个文件(范围错误或者Etag改变)。
Etag 由服务器端生成,客户端通过 If-Range 条件判断请求来验证资源是否修改。请求一个文件的流程如下:
第一次请求:
第二次请求(断点续传):
若不用If-Range,则需要发两次请求。因为若资源改变,会返回客户端412;客户端再发起请求,获得新资源
参考:
https://devcenter.heroku.com/articles/increasing-application-performance-with-http-cache-headers
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Conditional_requests