HTTP缓存 - pingdongyi/blog-2 GitHub Wiki
缓存有客户端浏览器缓存(HTTP缓存)、服务器端缓存(memcache缓存)、代理服务器的缓存(webserver缓存)和页面缓存(smarty或varnish缓存)等。
HTTP缓存是利用HTTP协议中的请求头及响应头进行设置,把web服务器的响应有条件的缓存的客户端浏览器中,以便在满足条件的情况下直接从本地缓存中返回请求内容,而不用再对服务器发起请求并返回数据。
- 减少了请求及数据的传输所用的带宽
- 减少了服务器的负担
- 加快了客户端浏览器加载页面的速度,大大提高了网站的性能
通过服务器提供正确适当的HTTP头指令来指引浏览器什么时候进行缓存及缓存多长时间。
HTTP缓存是通过ETag来判断是否使用缓存的,即ETag是浏览器缓存的条件或依据。
服务器通过ETag头传递验证令牌,并通过验证令牌进行资源更新检查,如果资源未更新,则不会传输任何数据。
假设在首次获取资源 120 秒之后,浏览器又对该资源发起了新请求。首先,浏览器会检查本地缓存并找到之前的响应,不幸的是,这个响应现在已经’过期’,无法在使用。此时,浏览器也可以直接发出新请求,获取新的完整响应,但是这样做效率较低,因为如果资源未被更改过,我们就没有理由再去下载与缓存中已有的完全相同的字节。
这就是 ETag 头中指定的验证令牌所要解决的问题:服务器会生成并返回一个随机令牌,通常是文件内容的哈希值或者某个其他指纹码。客户端不必了解指纹码是如何生成的,只需要在下一个请求中将其发送给服务器,如果指纹码仍然一致,说明资源未被修改,我们就可以跳过下载。并返回304 Not Modified响应,告诉浏览器缓存的资源没有更新,可以继续使用,这样也节约了时间和带宽。
我们唯一要做的就是确保服务器提供必要的 ETag 令牌:查看服务器文档中是否有必要的配置标志。流行服务器配置样例
# CSS and Javascript
location ~* \.(?:css|js)$ {
expires 1y;
access_log off;
add_header Cache-Control "public";
}
使用ETag的好处:
-
某些服务器不能精确得到文件的最后修改时间, 这样就无法通过最后修改时间来判断文件是否更新了。
-
某些文件的修改非常频繁,在秒以下的时间内进行修改. Last-Modified只能精确到秒。
-
一些文件的最后修改时间改变了,但是内容并未改变。 我们不希望客户端认为这个文件修改了。
每个资源都可以通过 Cache-Control HTTP 头来定义自己的缓存策略
Cache-Control指令控制谁在什么条件下可以缓存响应以及可以缓存多久
最好的请求是不必与服务器进行通信的请求:通过响应的本地副本,我们可以避免所有的网络延迟以及数据传输的数据成本。为此,HTTP 规范允许服务器返回 不同的Cache-Control指令,控制浏览器或者其他中继缓存如何缓存某个响应以及缓存多长时间。
在HTTP/1.1规范中用Cache-Control指令取代了之前的响应策略头,如Expires,现在所有的浏览器都已支持Cache-Control头。如果Cache-Control和Expires头都存在,则优先使用Cache-Control头。
请求报文
-
no-cache
在重新向服务器验证之前,不要返回文档的缓存副本,即需要请求服务器进行验证,但不一定需要返回文档内容
-
no-store
不要返回文档的缓存副本。不要保存服务器的响应,即不使用缓存内容
-
max-age
缓存中的文档不能超过指定的使用期
-
max-stale
文档允许过期,但不能超过指令中指定的过期值
-
min-fresh
文档的使用期不能小于这个指定的时间与它的当前时间之和。换句话说,响应必须至少在指定的这段时间之内保持新鲜,即可以过期,但可以在过期后指定的一段时间内
-
no-transform
文档在发送之前不允许被转换
-
only-if-cached
只有当文档在缓存中才发送,不要联系原始服务器
响应报文
-
public
响应可以被任何服务器缓存,大多数情况下,public不是必须的,因为明确的缓存信息(例如max-age)已表示响应可以被缓存
-
private
响应可以被缓存,但只能被单个端访问,只为单个用户缓存,因此,不允许任何中继缓存对其时进行缓存。例如用户浏览器可以缓存包含用户私人信息的HTML网页,但是CDN不能缓存
-
no-cache
表示必须先与服务器确认返回的响应是否被更改,然后才能使用该响应来满足后续对同一个网址的请求。因此,如果存在合适的验证令牌 (ETag),no-cache 会发起往返通信来验证缓存的响应,如果资源未被更改,可以避免下载
-
no-store
响应不允许被缓存,直接禁止浏览器和所有中继缓存存储返回的任何版本的响应。例如一个包含个人隐私数据或银行数据的响应,每次用户请求该资源时都会向服务器发送一个请求,每次都会下载完整的响应
-
must-revalidate
响应在提供给客户端之前必须重新向服务器验证
-
proxy-revalidate
共享的缓存在提供给客户端之前必须重新向原始服务器验证。私有的缓存可以忽略这条指令
-
max-age
指定文档可以被缓存的时间以及新鲜度的最长时间
-
s-max-age
指定文档作为共享缓存时的最长使用时间。私有的缓存可以忽略本指令
不存在最佳的缓存策略,根据您的通信模式、提供的数据类型以及应用特定的数据更新要求来定义,必须定义和配置每个资源最适合的设置以及整体的’缓存层级’。
要注意以下几点:
-
使用一致的网址
不同网址会缓存重复内容,网址区分大小写
-
确保服务器提供验证令牌 (ETag)
通过验证令牌,如果服务器上的资源未被更改,就不必传输相同的字节
-
确定中继缓存可以缓存哪些资源
对所有用户的响应完全相同的资源很适合由 CDN 或其他中继缓存进行缓存
-
确定每个资源的最优缓存周期
不同的资源可能有不同的更新要求。审查并确定每个资源适合的 max-age
-
确定网站的最佳缓存层级
对 HTML 文档组合使用包含内容指纹码的资源网址以及短时间或 no-cache 的生命周期,可以控制客户端获取更新的速度
-
搅动最小化
有些资源的更新比其他资源频繁。如果资源的特定部分(例如 JavaScript 函数或一组 CSS 样式)会经常更新,应考虑将其代码作为单独的文件提供。这样,每次获取更新时,剩余内容(例如不会频繁更新的库代码)可以从缓存中获取,确保下载的内容量最少
- CTRL+F5强制刷新浏览器,使浏览器不使用缓存
- 按F5刷新浏览器, 浏览器会去Web服务器验证缓存
- 在地址栏输入网址访问,浏览器会"直接使用有效的缓存", 而不去服务器验证缓存,即缓存命中
- Cache-Control: public 指可以公有缓存, 可以是数千名用户共享的
- Cache-Control: private 指只支持私有缓存, 私有缓存是单个用户专用的