Web缓存一般分为浏览器缓存、代理服务器缓存以及网关缓存,本文主要讲的是 浏览器缓存,其它两种缓存大家自行去了解下。
Web 缓存游走于服务器和客户端之间。这个服务器可能是源服务器(资源所驻留的服务器),数量可能是1个或多个;这个客户端也可能是1个或多个。Web 缓存就在服务器-客户端之间搞监控,监控请求,并且把请求输出的内容(例如html页面、 图片和文件)(统称为副本)另存一份;然后,如果下一个请求是相同的 URL,则直接请求保存的副本,而不是再次麻烦源服务器。
使用缓存的2个主要原因:
试想现在的大型网站,随便一个页面都是一两百个请求,每天 pv 都是亿级别,如果没有缓存,用户体验会急剧下降(表现在等待请求的时间上)、同时服务器压力和网络带宽都面临严重的考验。
浏览器缓存控制机制有三种:HTML5离线存储和本地缓存、HTML Meta 标签、HTTP 协议缓存。
该种缓存机制是运用 HTMl5 新推出一些支持离线应用的 API 来进行数据的缓存,比如 appcache、sessionStorage、localStorage等等。
appcache 通过定义一个描述文件(manifest file)来列出要下载和缓存的资源,manifest file 示例如下:
CACHE MANIFEST
# Comment
file.js
file.css
然后在 html 中引用:
<html manifest="./xxx.manifest">
sessionStorage、localStorage 的基本用法如下:
// localStorage 用法相似
sessionStorage.set('name', 'laixiangran') // 存储数据
sessionStorage.get('name') // 获取数据 'laixiangran'
本文暂时就不详细介绍,后面我会单独介绍这块的内容。
使用 HTML Meta 标签,Web 开发者可以在 HTML 页面的 <head>
节点中加入 <meta>
标签,代码如下:
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
上述代码的作用是告诉浏览器当前页面不被缓存,每次访问都需要去服务器拉取。
使用上很简单,但只有部分浏览器可以支持,而且所有缓存代理服务器都不支持,因为代理不解析 HTML 内容本身。
HTTP 协议缓存是我们本文讲解的重点,它是通过 HTTP 头信息来控制缓存的,HTTP 头信息可以让你对浏览器和代理服务器如何处理你的副本进行更多的控制。他们在 HTML 代码中是看不见的,一般由 Web 服务器自动生成。但是,根据你使用的服务器,你可以在某种程度上进行控制。
浏览器第一次请求流程图:
该流程比较简单了,浏览器在第一次请求的时候不存在缓存,直接从浏览器请求,等请求返回结果之后再根据 HTTP 头信息将数据缓存在内存或者硬盘中。
浏览器再次请求时:
该流程就复杂多了,浏览器需要根据 HTTP 头信息来判断是否直接从缓存读取数据还是交由服务器来判断是否从缓存读取数据。
几种状态码的区别:
下面我们就从该流程中出现的 HTTP 状态码 200(from cache)和 304 来讲解 HTTP 协议缓存中的 HTTP 头信息。
这种 HTTP 状态码表示不访问服务器,直接从缓存(内存或者硬盘)读取数据。
看两张图:
从上面两张图,我们会看到状态码有点不一样,分别是 200(from memory cache)
以及 200(from diks cache)
,这两个的区别一个是从内存读取数据,一个是从硬盘读取数据,然后它们的先后顺序是先从内存读取,再从硬盘读取。这里我们就统称为 200(from cache)
。
出现 200(from cache)
这种情况,我们需要关注 Expires
和 Cache-control
这两种HTTP 头信息字段。
Expires 的中文意思是“有效期”。显然,就是告诉浏览器缓存的有效期。如果过期,缓存会检查源服务器以确定文件是否改变了。
Expires 头唯一的有效值是 HTTP 时间,其他值无效,不会去缓存的。注意:时间是格林威治时间(GMT),而不是本地时间。如下所示:
Expires: Mon, 29 Oct 2018 03:53:10 GMT
那么看我们上面的两张图中的 Expires,它都是到 2018-10-29 03:53:10 过期,而我们本次请求的时间 Date 是 2018-04-29 03:53:10,因此本次请求直接从缓存读取数据,返回 200(from cache)。
尽管 Expires 头很有用,但它有一定的局限性:
Cache-Control 与 Expires 的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存读取数据还是重新发请求到服务器读取数据。只不过 Cache-Control 的选择更多,设置更细致,如果同时设置的话,其优先级高于 Expires。
Cache-Control 有用的响应头包括:
使用如下所示:
Cache-Control: max-age=15811200
那么看我们上面的两张图中的 Cache-Control,它在当前请求成功后15811200秒内都是有效的,因此本次请求直接从缓存读取数据,返回 200(from cache)。如果从当前请求成功开始,过了15811200秒之后就会重新从服务器请求新数据。
当浏览器通过 Expires
或者 Cache-control
判断出缓存已经过期,那么就需要重新发送请求到服务器,让服务器判断当前缓存是否可以继续使用。
当服务器判断该缓存已经失效,那么就会返回新数据,HTTP 状态码为 200;
当浏览器判断该缓存还未失效,那么就会返回 HTTP 状态码为 304 (无需包体,节省流量),告知浏览器继续使用缓存。
那么通过哪些 HTTP 头信息字段来判断是否返回 200 还是 304 呢?那么我们就请出接下来的主角: Last-Modified/If-Modified-Since
及 Etag/If-None-Match
。这两个字段都需要配合 Cache-Control
使用。
Cache-Control
标识的 max-age
),发现资源具有 Last-Modified
声明,则再次向 web 服务器请求时带上 If-Modified-Since,表示请求时间。web服务器收到请求后发现有 If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源有被改动过,则响应资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应 HTTP 304 (无需包体,节省流量),告知浏览器继续使用缓存。这是在 HTTP 1.1 中引入了一个新的验证器。
Cache-Control
标识的 max-age
),发现资源具有 Etage 声明,则再次向 web 服务器请求时带上 If-None-Match (Etag 的值)。web 服务器收到请求后发现有 If-None-Match 则与被请求资源的相应校验串进行比对,决定返回 200 或 304。你可能会觉得使用 Last-Modified 已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要 Etag(实体标识)呢?HTTP1.1 中 Etag 的出现主要是为了解决几个 Last-Modified 比较难解决的问题:
Etag 是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified 与 ETag 是可以一起使用的,服务器会优先验证 ETag,一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回 304。
通过上面的介绍,我们知道 HTTP 协议缓存的机制,目的就是让你可以更灵活更细致的控制浏览器缓存,从而让你的网站的缓存更加友好,用户体验更完美。
下面这些技巧也可以让你网站的缓存更加友好:
Cache-Control: max-age
头信息的值设大一点。max-age
或过期时间实现缓存。Last-Modified
值。另外,当你更新站点的时候,只要上传改动的那些文件,而不要把整个站点都覆盖过去。SSL:全称 Secure Socket Layer – 安全套接层,为 Netscape 所研发,用以保障在 Internet 上数据传输之安全,利用数据加密 (Encryption) 技术,可确保数据在网络上的传输过程中不会被截取及窃听。目前一般通用的规格为 40 bit 的安全标准,美国则已推出 128 bit 的更高安全标准,但限制出境。只要 3.0 版本以上的 I.E. 或 Netscape 浏览器即可支持 SSL。
REDbot:REDbot = RED + robot,是个机器人,检查 HTTP 资源,看他们如何会表现,指出常见的问题,并提出改进建议。虽然它属于 HTTP 一致性测试仪,但却可以找到不少 HTTP 相关问题。
用户的一些行为会影响到浏览器的缓存,具体如下: