解密浏览器缓存机制

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

分类

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

1. 强缓存

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

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

强缓存主要是受 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 响应头。

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

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的示例:

从上面的描述中可以查看到 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 下测试的结果图:
                                   
                                                                                     浏览器强缓存


                                                                                     浏览器验证缓存


                                                                                     浏览器不缓存

上面的测试分别是通过在地址栏回车重新键入地址、 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);
                                                               

(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状态码。
                                     

常见问题

经常遇到如下问题均可能是浏览器缓存导致的问题,请大家注意留意:
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

【本文原发布于阿里云云享频道(阿里云官网首页-支持-云享),作者:烨烁(阿里云云享专家)】

时间: 2024-08-17 21:31:26

解密浏览器缓存机制的相关文章

浏览器缓存机制浅析

非HTTP协议定义的缓存机制 浏览器缓存机制,其实主要就是HTTP协议定义的缓存机制(如: Expires: Cache-control等).但是也有非HTTP协议定义的缓存机制,如使用HTML Meta 标签,Web开发者可以在HTML页面的<head>节点中加入<meta>标签,代码如下: <META HTTP-EQUIV="Pragma" CONTENT="no-cache"> 上述代码的作用是告诉浏览器当前页面不被缓存,每

浏览器缓存机制

最近在做项目过程中需要对部分文件数据进行缓存,于是整理一些关于浏览器缓存机制的信息 概要总结:1.Expires 过期时间2.Cache-Control 缓存机制 [max-age=300]缓存时间 300 表示5分钟3.Last-Modified 最后修改时间 对应在请求头部有If-Modified-Since4.Etag 唯一标识 由服务器生成 对应在请求头部有If-No-Match优先级:Etag > last-modified > Expires 浏览器缓存机制,其实主要就是HTTP协

浏览器缓存机制(2)-应用缓存

浏览器缓存机制(2)-应用缓存 在公司项目中,一些移动版的WEB页面恰好用到了应用缓存,故顺便写篇文章来总结下应用缓存方面的内容. 1.应用缓存简介 应用缓存(application cache)是HTML5提供的一套缓存机制,使得WEB应用可以离线运行.除了一些旧版本的IE外,现代浏览器如firefox,chrome,safari大部分都是支持HTML5标准的.使用应用缓存主要优势有: 离线浏览:用户可以在离线状态浏览网页内容. 速度更快: 因为数据存储在浏览器缓存中,浏览器只会下载服务器发生

浏览器缓存机制详解

对于浏览器缓存,相信很多开发者对它真的是又爱又恨.一方面极大地提升了用户体验,而另一方面有时会因为读取了缓存而展示了"错误"的东西,而在开发过程中千方百计地想把缓存禁掉.那么浏览器缓存究竟是个什么样的神奇玩意呢? 什么是浏览器缓存: 简单来说,浏览器缓存就是把一个已经请求过的Web资源(如html页面,图片,js,数据等)拷贝一份副本储存在浏览器中.缓存会根据进来的请求保存输出内容的副本.当下一个请求来到的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是

Java缓存学习之二:浏览器缓存机制

浏览器端的九种缓存机制介绍 浏览器缓存是浏览器端保存数据用于快速读取或避免重复资源请求的优化机制,有效的缓存使用可以避免重复的网络请求和浏览器快速地读取本地数据,整体上加速网页展示给用户.浏览器端缓存的机制种类较多,总体归纳为九种,这里详细分析下这九种缓存机制的原理和使用场景.打开浏览器的调试模式->resources左侧就有浏览器的8种缓存机制. 一.http缓存 http缓存是基于HTTP协议的浏览器文件级缓存机制.即针对文件的重复请求情况下,浏览器可以根据协议头判断从服务器端请求文件还是从

浏览器缓存机制(1)

浏览器缓存机制之一(经典缓存) 因为在接手的项目中用到过比较新的HTML5应用缓存,也用到了经典的缓存如设置max-age,Etag之类,而之前一直就是在用着没有去深究其中原理.周末天气不好,懒得出去了,正好找时间总结下. 1.关于浏览器缓存 记得去年看<HTTP权威指南>的时候,有一章是专门讲浏览器缓存的,一年时间过得太快,逝去的时光还真是如同人群中消失的好姑娘,眼看她嫁给别人.我这里把浏览器缓存分为经典的浏览器缓存(以下简称为经典缓存)和HTML5应用缓存这两类. 经典的浏览器缓存其实主要

atitit。浏览器缓存机制 and 微信浏览器防止缓存的设计 attilax 总结

atitit.浏览器缓存机制 and 微信浏览器防止缓存的设计 attilax 总结 1. 缓存的一些机制 1 1.1. http 304 1 1.2. 浏览器刷新的处理机制 1 1.3. Expires 2 1.4. Cache-Control 2 1.5. Last-Modified/E-tag 3 1.6. Etag 主要为了解决 Last-Modified 无法解决的一些问题. 4 2. 不同的页面打开方式产生的请求区别 5 3. html  meta法 5 4. http head 法

[转]浏览器缓存机制

浏览器缓存机制,其实主要就是HTTP协议定义的缓存机制(如: Expires: Cache-control等).但是也有非HTTP协议定义的缓存机制,如使用HTML Meta 标签,Web开发者可以在HTML页面的<head>节点中加入<meta>标签,代码如下: <META HTTP-EQUIV="Pragma" CONTENT="no-cache"> 上述代码的作用是告诉浏览器当前页面不被缓存,每次访问都需要去服务器拉取.使用

【转】浏览器缓存机制

最近在做页面分析的时候发现页面F5刷新时,大部分原来已经缓存的内容的状态变成了304,很是不解,原来想好好看看是什么原因的.结果发现园里已经有人分析的很彻底了. 原文地址:浏览器缓存机制 浏览器缓存机制,其实主要就是HTTP协议定义的缓存机制(如: Expires: Cache-control等).但是也有非HTTP协议定义的缓存机制,如使用HTML Meta 标签,Web开发者可以在HTML页面的<head>节点中加入<meta>标签,代码如下: <META HTTP-EQ