nginx 缓存能够让网页打开速度享受质的飞跃。 当我们第一次访问一个页面时 将下载的css,js,html已经img等相关资源保存在本地。 在第二次,第三次…访问时,就可以不用去下载文件了。
通常来说,设置文件的缓存有两种方式,一种是在服务器内设置响应头文件,另外一个是使用h5的manifest文件来进行相关设置.
服务器的缓存协商
这种方式设置的缓存有两种,一种是需要服务器验证,另外一种是不用发送请求验证。
ETag/Last-Modified
这两种方式做法类似,都要向服务器发送一次请求进行验证。简直,缓存就缓存呗,为什么还要验证呢? 其实,这是该协议的一种特有方式,发送一次验证主要是检查文件是否发生变化。
ETag
ETag是用来计算文件的内容是否发生变化,比如,你在文件中删除一个空格,这样都算文件内容发生变化。 通常做法是用md5或者SHA1算法,计算出文件的唯一值。 在前端其实都可以完成, 找到一个文件文件解析的md5算法,然后将文件传入,就可以得到ETag的值。 不过这里,我们着重点并不是让你生成Etag,而是看看ETag在缓存中的重要作用。
ETag是HTTP/1.1A的一种办法,由Web服务器生成,并写入响应头中。1
2//response Headers
ETag:"751F63A30AB5F98F855D1D90D217B356"
接着,到了浏览器之后,便缓存在本地。 当下次打开同样的文章时,会在请求头中发送If-None-Match, 给服务器检查文件是否发生变化。如果没有,则告诉浏览器使用本地的,否则返回新文件1
2//request Headers
If-None-Match: "751F63A30AB5F98F855D1D90D217B356"
通常情况下,服务器默认是打开Etag的,但是为了防止你的同事,或者后台哥哥的后台配置文件不正确,关闭了Etag,这时候,就需要你对对配置文件做一些设置。 这里我以Nginx为例:
打开ngnix.conf文件,检查是否有以下语句:1
2
3etag off;
more_set_headers -s 404 -t 'ETag';
more_clear_headers 'Etag';
如果有则将其删除掉。然后重启nginx就可以了。他们将Etag关闭的原因其实也很简单,就是因为,Etag打开之后会增加服务器的负载,造成性能的局限性,所以,关闭或者打开Etag都要经过权衡的。
Last-Modified
Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
这和文档内容信息验证不同,这里采用的是日期验证办法。 即服务器上会对文件打上一个文件改动的日期,然后客户端接受该日期,下次请求时,返回该日期,服务器验证,如果日期未变,则告诉浏览器使用本地缓存即可。
即在服务器的相应头中,可以设置Last-Modified,来启用这一缓存协议.1
2//Response Header
Last-Modified:Tue, 03 Mar 2015 01:38:18 GMT
接受到这一响应头之后,浏览器会对该文件做一个缓存,并保存该日期。当下次请求的时候,会通过If-Modified-Since将日期传入并验证:1
If-Modified-Since:Tue, 03 Mar 2015 01:38:18 GMT
如果日期未变,则告诉浏览器使用缓存。
那我们通常应该怎样启用服务器这一功能呢?
默认情况下,服务器会对静态资源发送Last-modified的tag。 但是,需要注意,Last-Modified的更新时间只能以秒来计,如果你文件改动过于频繁,Last-Modified是无效的(不过,谁牛逼到1s内能多次更新文件嘞~)
实际上Last-Modified的这个标签的我们通常并不会单独使用它,通常与expires结合,形成一个可降级的缓存.
Last-Modified/If-Modified-Since要配合Cache-Control使用。
Expires/Cache-Control
Expires/Cache协议与上述验证协议最大的不同在于,他可以省略发送验证请求环节,不需要服务器的验证,而直接使用本地缓存。 通常这种方式,适用于,项目稳定,版本迭代不多的时候。
Expires
1 | //Response Headers |
这告诉浏览器,在2016.5.3号之前,可以直接使用该文本的缓存副本。但是,可能会因为服务器和客户端的GMT时间不同,会有一定的bug。 所以,这里只提议在长时间缓存的情况下使用。否则,应该选择Cache-Control.
以Nginx服务器为例:
对于不经常修改的静态内容(如图片,JS,CSS),可以在服务器中设置expires过期时间,控制浏览器缓存,达到有效减小带宽流量,降低服务器压力的目的。1
2
3location ~ .*\.(js|css)$ {
expires 10d;
}
过期时间为10天,js css文件不怎么更新,过期可以设大一点,如果频繁更新,则可以设置得小一点。
通过expires设置过期时间为一天,此时,服务器会根据当前的时间,加上一天.同时添加Expires和Cache-Control头部标签。
即,得到的Response Header为:1
2Expires: Fri, 28 Feb 2016 10:42:09 GMT
Cache-Control: max-age=864000 //24*60*6
(HTTP规定,如果出现max-age和expires,则max-age默认覆盖掉expires)
当expires为负数表示no-cache,正数或零表示max-age=time。
如果你不想缓存,可以直接设置:1
expires -1; //永远过期,Cache-Control: no-cache
详细可以直接参阅:nginx配置
Cache-Control
这应该是HTTP1.1为了解决HTTP1.0中expires的时间差的bug,而新添加的一个tag. 他的配置项很多,其实完全都可以取代expires(现在大多数服务器都支持). 引用一段原话:
Cache-Control 头在 HTTP/1.1 规范中定义,取代了之前用来定义响应缓存策略的头(例如 Expires)。当前的所有浏览器都支持 Cache-Control,因此,使用它就够了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 General
Request URL: https://www.sundayle.com/home/images/logo.png
Request Method: GET
Status Code: 200 (from memory cache)
Remote Address: 123.31.46.176:443
Referrer Policy: no-referrer-when-downgrade
Response Headers
accept-ranges: bytes
cache-control: max-age=2592000
content-length: 3559
content-type: image/png
date: Thu, 31 May 2018 03:27:29 GMT
etag: "5ac1d72f-de7"
expires: Sat, 30 Jun 2018 03:27:29 GMT
last-modified: Mon, 02 Apr 2018 07:09:35 GMT
server: nginx
status: 200
当前每次发送请求之前浏览器会检查缓存系统里,是否有相应文件的备份,如果有的话,则直接从本地模仿一个Response头
理论知识铺垫完毕,我们来take a look. 看看cache-control 有哪些可以配置的属性(以下属性都跟在cache-control后)
- public: 共有缓存,可被缓存代理服务器缓存,比如CDN
- private: 私有缓存,这些响应通常只为单个用户缓存,因此不允许任何中间缓存对其进行缓存。例如,用户的浏览器可以缓存包含用户私人信息的 HTML 网页,但 CDN 却不能缓存。
- max-age=[秒]:表示在这个时间范围内缓存是新鲜的无需更新。类似Expires时间,不过这个时间是相对的,而不是绝对的。也就是某次请求成功后多少秒内缓存是新鲜的。
- s-maxage=[秒]:类似max-age, 除了仅应用于共享缓存(如代理)。
- no-cache:这里不是不缓存的意思,只是每次在使用缓存之前都强制发送请求给源服务器进行验证,检查文件该没改变(其实这里和ETag/Last区别不大)
- no-store:就是禁止缓存,不让浏览器保留缓存副本
- must-revalidate:告诉浏览器,你这必须再次验证检查信息是否过期, 返回的代号就不是200而是304了。
- proxy-revalidate:类似must-revalidate,除了只能应用于代理缓存。
比如,这里我可以设置Cache-Control为:1
2//Response Headers
Cache-Control:private, max-age=0, must-revalidate
该文件是一个私有文件,只能被浏览器缓存,而不能被代理缓存。max-age标识该缓存立即过期,其实和no-cache实际上区别不大. 然后must-revalidate告诉浏览器,你必须给我再验证文件过没过期,比如接下来可能会验证Last-Modified或者ETag.如果没有过期则使用本地缓存.
其实上面可以直接等同于:1
2//Response Headers
Cache-Control:private,no-cache
使用no-store的结果1
2//Response Headers
Cache-Control:no-store;
这样表明,不管一不一样都需要重新下载. 强烈表示,不让你使用缓存文件。后续的就不会去验证ETag了。
当然,如果你将IE6那种古老的浏览器考虑进来的话,那你干脆就做的不要脸一点,直接用下面的tag就行:1
2
3Cache-Control: no-cache, no-store, must-revalidate //HTTP1.1
Pragma: no-cache //HTTP1.0
Expires: 0 //Proxy
不过现在基本上也没有不支持Cache-Control的浏览器了。所以,正常情况下,可以直接使用.如下的策略来进行设置:[From google developer(https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-cn)]
定义最佳 Cache-Control 策略
我们通常在nginx怎么配置对应的cache-control头呢?1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16##设置no-cache
//Nginx
expires -1;
//cache-control
Cache-Control:no-cache
##设置max-age=0
//Nginx
expires 0;
//cache-control
Cache-Control:max-age=0
##设置其他头部
//nginx
add_header Cache-Control "no-cache";
add_header Pragma no-cache;
上面说的基本上是服务器的响应头,那在浏览器的Request headers里存在cache-control代表什么呢?
当请求头中有:Cache-Control: max-age=0,表示缓存需要进行验证(ETag||Last-Modified),如果缓存未过期,则可以使用。
当请求头中有:Cache-Control: no-cache,表示浏览器只能获取最新的文件。 和Response Header中的no-store相对应。
在开发调试web的时候,经常会碰到因浏览器缓存(cache)而经常要去清空缓存或者强制刷新来测试的烦恼,提供下apache不缓存配置和nginx不缓存配置的设置。在常用的缓存设置里面有两种方式,都是使用add_header来设置:分别为Cache-Control和Pragma。
1 | location ~ .*\.(css|js|swf|php|htm|html )$ { |
http://www.web3.xin/code/1763.html
https://segmentfault.com/a/1190000004486640
https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-cn