一文搞懂浏览器缓存机制( 三 )

服务器端文件的最后修改时间 , 需要和cache-control共同使用 , 是检查服务器端资源是否更新的一种方式 。当浏览器再次进行请求时 , 会向服务器传送If-Modified-Since报头 , 询问Last-Modified时间点之后资源是否被修改过 。如果没有修改 , 则返回码为304 , 使用缓存;如果修改过 , 则再次去服务器请求资源 , 返回码和首次请求相同为200 , 资源为服务器最新资源 。
4. Etag & & If-None-Match
根据实体内容生成一段hash字符串 , 标识资源的状态 , 由服务端产生 。浏览器会将这串字符串传回服务器 , 验证资源是否已经修改 , 如果没有修改 , 过程如下:

一文搞懂浏览器缓存机制

文章插图
 
2.2.3 缓存报头种类与优先级
1. Cache-Control与Expires
Cache-Control与 Expires的作用一致 , 都是指明当前资源的有效期 , 控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据 。只不过 Cache-Control的选择更多 , 设置更细致 , 如果同时设置的话 , 其优先级高于 Expires 。
2. Last-Modified与ETag
你可能会觉得使用 Last-Modified 已经足以让浏览器知道本地的缓存副本是否足够新 , 为什么还需要 Etag(实体标识)呢?HTTP1.1中Etag的出现主要是为了解决几个 Last-Modified 比较难解决的问题:
  • Last-Modified 标注的最后修改只能精确到秒级 , 如果某些文件在1秒钟以内 , 被修改多次的话 , 它将不能准确标注文件的新鲜度
  • 如果某些文件会被定期生成 , 当有时内容并没有任何变化 , 但 Last-Modified 却改变了 , 导致文件没法使用缓存
  • 有可能存在服务器没有准确获取文件修改时间 , 或者与代理服务器时间不一致等情形
Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符 , 能够更加准确的控制缓存 。Last-Modified与ETag是可以一起使用的 , 服务器会优先验证ETag , 一致的情况下 , 才会继续比对Last-Modified , 最后才决定是否返回304 。Etag的服务器生成规则和强弱Etag的相关内容可以参考 , 《互动百科-Etag》和《HTTP Header definition》 , 这里不再深入 。
3. Last-Modified/ETag 与 Cache-Control/Expires
配置 Last-Modified/ETag的情况下 , 浏览器再次访问统一URI的资源 , 还是会发送请求到服务器询问文件是否已经修改 , 如果没有 , 服务器会只发送一个304回给浏览器 , 告诉浏览器直接从自己本地的缓存取数据;如果修改过那就整个数据重新发给浏览器;
Cache-Control/Expires则不同 , 如果检测到本地的缓存还是有效的时间范围内 , 浏览器直接使用本地副本 , 不会发送任何请求 。两者一起使用时 ,  Cache-Control/Expires的优先级要高 , 即当本地副本根据 Cache-Control/Expires发现还在有效期内时 , 则不会再次发送请求去服务器询问修改时间 Last-Modified或实体标识 Etag了 。
一般情况下 , 两者会配合一起使用 , 因为即使服务器设置缓存时间, 当用户点击“刷新”按钮时 , 浏览器会忽略缓存继续向服务器发送请求 , 这时 Last-Modified/ETag将能够很好利用304 , 从而减少响应开销 。
2.2.4 哪些请求不能被缓存?
无法被浏览器缓存的请求:
  • HTTP信息头中包含Cache-Control:no-cache , pragma:no-cache , 或Cache-Control:max-age=0等告诉浏览器不用缓存的请求
  • 需要根据Cookie , 认证信息等决定输入内容的动态请求是不能被缓存的
  • 经过HTTPS安全加密的请求(有人也经过测试发现 , ie其实在头部加入Cache-Control:max-age信息 , firefox在头部加入Cache-Control:Public之后 , 能够对HTTPS的资源进行缓存 , 参考《HTTPS的七个误解》)
  • POST请求无法被缓存
  • HTTP响应头中不包含Last-Modified/Etag , 也不包含Cache-Control/Expires的请求无法被缓存
3. 使用缓存流程
一个用户发起一个静态资源请求的时候 , 浏览器会通过以下几步来获取并展示资源:


推荐阅读