解密浏览器缓存机制-阿里云开发者社区

开发者社区> 烨烁> 正文

解密浏览器缓存机制

简介: Web 缓存是在 HTTP 协议中常见的一种机制,可以有效的提升客户端响应速度、降低源站负载带宽。Web 缓存的一个重要特性就是层次性,因此从客户端到源站服务器中间可能会包含多级缓存,包括本地客户端缓存、公共代理缓存、Web 服务器缓存等。本文主要为大家讲解本地浏览器缓存相关机制。
+关注继续查看

浏览器缓存是节省用户流量,提升加载效率的常用方法;但同时它也会带来获取到历史脏数据等风险,今天我们就来详细介绍下浏览器缓存相关内容。

分类

浏览器的缓存主要包括两种缓存:强缓存、验证缓存。

1. 强缓存

强缓存是指浏览器不与服务器进行任何交互请求,直接将浏览器的缓存数据(包括缓存数据的 Response 头信息)返回给用户。这种缓存给用户的响应是最快的,但同时也是风险性较高的。因为该类缓存没有进行任何的校验即直接反馈给用户,是可能存在有历史的脏数据。当浏览器的请求出现同时以下两个现象时该次请求就是强缓存:

  1. 浏览器返回200 (From Cache):
    image


  1. 请求 Response 头中的 Date 字段所表示的时间小于当前时间:

                                     image


强缓存主要是受 Cache-Control:max-age 和 Expires 头两个 Http 响应头控制的。 Cache-Control 头和 Expires 头都是都是缓存数据的有效期的信息。只不过 HTTP/1.0+ 的 Expires 头是采用的绝对 GMT 时间,而 HTTP/1.1 的 Cache-Control:max-age 则是采用的相对时间进行存储。在实际使用中我们更倾向于使用 Cache-Control:max-age 头,因为 Expires 头记录的是服务器端设置的绝对时间;如果客户端与服务器之间的时间差别较大的话可能会导致有偏差;并且当 Cache-Control:max-age 和 Expires 头同时存在的情况下, Cache-Control 头将覆盖 Expires 头。当请求发起的时间仍然在 Cache-Control 或者 Expires 设置的有效期内的话则将直接读取缓存数据。

读取强缓存的数据将是最快响应数据的方法,因为该次请求没有产生任何实际的公网访问,而仅仅是获取本地的数据即可。

2. 验证缓存

验证缓存(又叫协商缓存)是指浏览器根据缓存资源的 Last-Modified 字段和 Etag 字段得到 If-Modified-Since 和 If-None-Match 字段加入 Request 头中向服务器进行验证源站服务器的资源是否有更新过,如果服务器端收到该请求并且发现服务器端资源没有进行变更即会返回 304 Not Modified 响应头。


                                                image

  下面分别介绍这几个字段的意义:
  Last-Modified / If-Modified-Since :在客户端第一次向服务器端发起请求时,服务器返回数据并置状态码为200,同时将该文件最后修改的 GMT 时间记录在 Last-Modified 头中返回客户端。下次客户端请求验证缓存数据时就会将缓存数据中的 Last-Modified 字段记录为请求头中的 If-Modified-Since 字段向服务器端询问在该时间点后服务器的文件是否有做过更新,如果没有更新即返回 304 Not Modified 响应头并读取缓存数据,而如果服务器文件该时间点后更新过则需要重新将服务器的文件传输给客户端并返回200状态码,同时该文件的 Last-Modified 时间也将是服务器文件现在更新的时间。下图就是一个客户端发送 If-Modified-Since 请求头给服务器端,然后服务器端验证完成后返回304给客户端。



                                                                      image

  Etag / If-None-Match : HTTP 协议规格说明定义 ETag 为“被请求变量的实体值”。另一种说法是, ETag 是一个可以与 Web 资源关联的记号(token)。 HTTP/1.1 并没有要求具体 ETag 中间需要存放什么内容或者实现方法,有一些 ETag 是通过文件资源的 MD5 值来进行标识的。与 Last-Modified 一样也是判断服务器文件是否有做过更新,其也是将上次缓存数据中的 ETag 记录为请求头中的 If-None-Match 头向服务器验证服务器文件的 ETag 是否更新过。 ETag 验证主要解决以下几点 Last-Modified 无法解决的问题:
  1. 网站文件周期性更新但并不改变文件内容(仅修改 Last-Modified 时间),对于这些文件仍然希望可以使用缓存数据;
  2. 网站文件更新频率较快,小于秒级的更新频率通过 Last-Modified 无法识别;
  3. 服务器无法准确得到 Last-Modified 时间,需要 ETag 标识文件。
    下图就是根据 If-None-Match 验证服务器端的 ETag 后返回304的示例:



                                                                      image

从上面的描述中可以查看到 304 是将本地缓存的 Last-Modified 和 ETag 与服务器端进行校验,因此校验缓存相比于强缓存不会出现读取本地脏数据的情况,而校验缓存的请求时间相比于强缓存较慢,而相比于完整获取服务器端的文件是较小的。因为校验缓存仍然是需要发请求到服务器端,但是 304 响应内容数据较小,因此比直接获取源文件更高效。

浏览器行为

不仅仅服务器端的 ETag 或者 Last-Modified 头会影响浏览器缓存策略,同时浏览器本身的请求头也同样会影响缓存策略。例如:浏览器有多种刷新行为可以影响下次请求对缓存数据的行为,并且不同的浏览器对于同样的刷新操作也有不同的情况。究其根本原因都是浏览器在发起请求的时候所带的 Catch-Control 的头信息来决定的。下面是 HTTP/1.1 文档中 13.2.6 Disambiguating Multiple Responses 的一段文档描述了该问题 [1]:

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.

从上面该文档可以知晓:如果浏览器想忽略强缓存的数据而直接获取验证缓存的数据的话是需要在请求头中加上 Cache-Control:max-age=0;而浏览器如果想忽略强缓存和鉴权缓存,直接获取源服务器的内容而缓存数据就需要在请求头中加上 Cache-Control:no-cache 的头。下面是在 Chrome 下测试的结果图:
                                   image
                                                                                     浏览器强缓存


                                   image
                                                                                     浏览器验证缓存


                                   image
                                                                                     浏览器不缓存


上面的测试分别是通过在地址栏回车重新键入地址、 F5 刷新以及 Ctrl+F5 刷新的测试结果。从上面的测试结果图中可以查看到与上述的结论一致;并且对于 Cache-Control: no-cache 的测试中为了兼容 HTTP/1.0 加上了 Pragma:no-cache 的头信息,其作用于前者是一致的。因此不同的浏览器对于不同的刷新操作有不同的处理逻辑也是由 Request 头中的 Cache-Control 头决定的。

流程总结

下面将根据两张图 [2] [3] 总结浏览器缓存的处理逻辑。

 (1)当浏览器向服务器端发送请求的时候首先查看本地浏览器缓存数据中是否有缓存数据,如果没有缓存数据则会向 Web 服务器(这里的 Web 服务器是广义的概念,有可能并不是源站服务器,有可能是 CDN 等缓存数据)请求对应的数据并将获取的响应数据以及一些对应的 Response 头信息缓存到本地(包括 Expires 、Cache-Control 等头信息),如果有缓存数据则执行(2);

                                                               image


(2)当本地有缓存数据并且 Request 头中没有设置 Cache-Control:no-cache 和 Cache-Control:max-age=0 头信息的话就需要查看该缓存的 Cache-Control 头和 Expires 头查看该缓存数据是否新鲜,如果没有过期则直接读取强缓存数据返回给浏览器,返回状态码 200(From Cache) 。如果有设置上述的两个 Cache-Control 头或者强缓存数据已经过期则执行(3);

 (3)如果请求头中没有 Cache-Control:no-cache 头信息的话则客户端带着 If-Modified-Since 和 If-None-Match 参数向服务器发起验证,如果服务器端验证发现没有进行更新的话则直接返回 304 Not  Modified 头和本地的缓存数据返回给客户端。如果请求头带了 Cache-Control:no-cache 或者源站做了更新则执行(4);
 (4)如果请求头中有 Cache-Control:no-cache 或者验证缓存校验发现源站数据更新了,则需要从服务器重新获取数据并将其存入浏览器缓存并返回200状态码。

                                     image

常见问题

经常遇到如下问题均可能是浏览器缓存导致的问题,请大家注意留意:

  1. 添加CDN 加速源站后,客户端访问出现历史脏数据。由于添加 CDN 后浏览器到服务器端可能出现缓存的就是浏览器缓存、CDN 缓存,因此需要清楚两处的缓存后测试是否正常,如果仍然获取到脏数据有可能出现劫持的情况导致的,用户可以通过查看响应头中是否有出现 301 或者 302 的状态码查看。
  2. CDN 可以设置响应 HTTP 头中的 Cache-Control 和 Expires 头,这两个头与 HTTP 标准协议一致的设置方法: Cache-Control 可以设置相对时间,而 Expires 仅能够设置绝对 GMT 时间。在 CDN 上设置的 Cache-Control 和 Expires 头将仅影响浏览器缓存,并不影响 CDN 缓存策略。 CDN 的缓存策略需要源站的 Cache-Control 和 Expires 头决定。
  3. 当源站响应头中设置了如下的缓存策略 CDN 和浏览器都将认为是源站不允许缓存而不进行缓存:
  • Cache-Control为no-cache,no-store,private
  • Cache-Control为max-age=0
  • Pragma为no-cache

Reference

[1] Hypertext Transfer Protocol -- HTTP/1.1: https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
[2] HTTP 权威指南
[3] 缓存系列(1)——浏览器缓存协商: http://blog.csdn.net/chosen0ne/article/details/7344189
[4] http协商缓存VS强缓存: http://www.cnblogs.com/wonyun/p/5524617.html
[5] stackoverflow讨论帖: http://stackoverflow.com/questions/1046966/whats-the-difference-between-cache-control-max-age-0-and-no-cache

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
10086 0
C++实践参考——二进制文件浏览器
【项目-二进制文件浏览器】 (1)做一个类似BinaryViewer的查看二进制文件的程序,输入文件名后,可以以16进制和ASCII对照的方式列出该文件的内容,可以参考下图: 提示:循环中,一次读入16个字节,先用16进制形式输出,再用字符形式输出。 [参考解答] #include<iostream> #include<iomanip&g
869 0
清除浏览器缓存的方法
清除浏览器缓存的方法 1 避免HTML页面缓存  在页面中的中添加      2  jquery ajax清除浏览器缓存   1 cache:false eg: $.ajax({ url:'', dataType:'json', data:{}, ...
611 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13891 0
js文件被浏览器缓存的思考
  我们的用户量大,修改js文件后,用户反馈登录出现问题。实际上刷新一下就没事了。就是因为用户的浏览器使用的还是本地缓存的js代码。   强制刷新一般就会重新去服务器获取新的js代码。但不能让用户每次都这样子去做。
1046 0
九种浏览器端缓存机制知多少(转)
浏览器缓存(Browser Caching)是浏览器端保存数据用于快速读取或避免重复资源请求的优化机制,有效的缓存使用可以避免重复的网络请求和浏览器快速地读取本地数据,整体上加速网页展示给用户。浏览器端缓存的机制种类较多,总体归纳为九种,这里详细分析下这九种缓存机制的原理和使用场景。
883 0
fbh
Chrome浏览器强制刷新页面(不使用缓存)
在Chrome浏览器中按下F5或 Ctrl+F5 都没用,Chrome总是会强制使用页面缓存进行刷新,如何不使用页面缓存进行刷新? Chrome官方推荐使用如下快捷键,就可以不使用页面缓存进行刷新 Windows和Linu...
3973 0
+关注
烨烁
专注于阿里云存储、加速与视频相关内容。
15
文章
2
问答
来源圈子
更多
作为全球云计算的领先者,阿里云为全球230万企业提供着云计算服务,服务范围覆盖200多个国家和地区。我们致力于为企业、政府等组织机构提供安全可靠的云计算服务,给用户带来极速愉悦的服务体验。
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载