HTTP Headers
1. 通用首部字段:就是请求报文和响应报文都能用上的字段
通用首部字段2. 请求首部字段
请求首部字段3. 响应首部字段
响应首部字段4. 实体首部字段:提供实体相关的附加信息
实体首部字段Cache-Control
Cache-Control也是一个通用首部字段,这意味着它能分别在请求报文和响应报文中使用。在RFC中规范了 Cache-Control 的格式为:
"Cache-Control" ":" cache-directive
作为请求首部时,cache-directive 的可选值有:
请求首部里的cache-directive作为响应首部时,cache-directive 的可选值有:
响应首部里的cache-directive问题讨论:
s-maxage与max-age:分别针对共享缓存与本地缓存
引自HTTP Protocal 14.9.3
s-maxage
If a response includes an s-maxage directive, then for a shared cache (but not for a private cache), the maximum age specified by this directiveoverridesthe maximum age specified by either the max-age directive or the Expires header.
cdn - HTTP Header Cache Time: s-maxage and max-age - Webmasters Stack Exchange
no-cache与max-age=0:
引自HTTP Protocal 13.2.6
When a client tries to revalidate a cache entry, and the response it receives contains a Date header that appears to be older than the one for the existing entry, then the client SHOULD repeat the request unconditionally, and include
Cache-Control: max-age=0
to force any intermediate caches to validate their copies directly with the origin server, or
Cache-Control: no-cache
to force any intermediate caches to obtain a new copy from the origin server.
http - What's the difference between Cache-Control: max-age=0 and no-cache? - Stack Overflow
缓存校验字段
1. Last-Modified
服务器将资源传递给客户端时,会将资源最后更改的时间以“Last-Modified: GMT”的形式加在实体首部上一起返回给客户端。
客户端会为资源标记上该信息,下次再次请求时,会把该信息附带在请求报文中一并带给服务器去做检查,若传递的时间值与服务器上该资源最终修改时间是一致的,则说明该资源没有被修改过,直接返回304状态码即可。
至于传递标记起来的最终修改时间的请求首部字段一共有两个:
⑴ If-Modified-Since: Last-Modified-value
示例为
If-Modified-Since:Thu,31Mar201607:07:52GMT
该请求首部告诉服务器如果客户端传来的最后修改时间与服务器上的一致,则直接回送304 和响应报头即可。
当前各浏览器均是使用的该请求首部来向服务器传递保存的 Last-Modified 值。
⑵ If-Unmodified-Since: Last-Modified-value
告诉服务器,若Last-Modified没有匹配上(资源在服务端的最后更新时间改变了),则应当返回412(Precondition Failed) 状态码给客户端。
当遇到下面情况时,If-Unmodified-Since 字段会被忽略:
1.Last-Modified值对上了(资源在服务端没有新的修改);
2.服务端需返回2XX和412之外的状态码;
3.传来的指定日期不合法
Last-Modified 说好却也不是特别好,因为如果在服务器上,一个资源被修改了,但其实际内容根本没发生改变,会因为Last-Modified时间匹配不上而返回了整个实体给客户端(即使客户端缓存里有个一模一样的资源)。
2. ETag
为了解决上述Last-Modified可能存在的不准确的问题,Http1.1还推出了 ETag 实体首部字段。
服务器会通过某种算法,给资源计算得出一个唯一标志符(比如md5标志),在把资源响应给客户端的时候,会在实体首部加上“ETag: 唯一标识符”一起返回给客户端。
客户端会保留该 ETag 字段,并在下一次请求时将其一并带过去给服务器。服务器只需要比较客户端传来的ETag跟自己服务器上该资源的ETag是否一致,就能很好地判断资源相对客户端而言是否被修改过了。
如果服务器发现ETag匹配不上,那么直接以常规GET 200回包形式将新的资源(当然也包括了新的ETag)发给客户端;如果ETag是一致的,则直接返回304知会客户端直接使用本地缓存即可。
那么客户端是如何把标记在资源上的 ETag 传去给服务器的呢?有两个请求首部字段可以带上 ETag 值:
⑴ If-None-Match: ETag-value
示例为
If-None-Match:"56fcccc8-1699"
告诉服务端如果 ETag 没匹配上需要重发资源数据,否则直接回送304 和响应报头即可。
当前各浏览器均是使用的该请求首部来向服务器传递保存的 ETag 值。
⑵ If-Match: ETag-value
告诉服务器如果没有匹配到ETag,或者收到了“*”值而当前并没有该资源实体,则应当返回412(Precondition Failed) 状态码给客户端。否则服务器直接忽略该字段。
If-Match 的一个应用场景是,客户端走PUT方法向服务端请求上传/更替资源,这时候可以通过 If-Match 传递资源的ETag。
需要注意的是,如果资源是走分布式服务器(比如CDN)存储的情况,需要这些服务器上计算ETag唯一值的算法保持一致,才不会导致明明同一个文件,在服务器A和服务器B上生成的ETag却不一样。
缓存示意图
第一次请求
第一次请求流程第一次请求,无论是静态文件还是其他文件,都是从服务器那里读取的。因此没有缓存之说。等第一次请求完,浏览器就有缓存了,然后整个的加载过程就完全不一样了。
再次请求
再次请求流程浏览器再次请求,情况就不一样了:
1. 首先会读取缓存,然后根据Expires或Cache-Control判断缓存是否过期,如果不过期,就直接读取缓存。
2. 否则,判断浏览器返回的头部信息是否存在Etag,如果存在,浏览器会像服务器发送带有If-None-Match的请求头,来和服务器返回的Etag做对比,如果if-None-Match和Etag相等。说明缓存没有更新,服务器返回304,浏览器继续从缓存读取相应的内容。如果if-None-Match和Etag不等,则服务器返回200,浏览器需要重新从服务器获取内容。
3. 如果服务器的返回信息里面没有Etag,则判断浏览器的返回信息里是否有Last-Modified。如果有,浏览器会像服务器发送一个if-Modified-Since的请求头。然后if-Modified-Since的值会和Last-Modified的值做对比,如果if-Modified-Since的值大于等于Last-Modified,则服务器返回304,文件没有更新,直接读取缓存即可。如果if-Modified-Since的值小于Last-Modified。则说明浏览器的缓存不是最新的,需要从服务器重新读取。
4. 如果服务器返回的头部信息既没有Etag,又没有Last-Modified,则缓存已经失效了,重新服务器抓取。
参考:
cdn与http缓存 - HackerVirus - 博客园
网友评论