缓存的目的是,减少客户端和服务器之间数据传输,以此来达到减少服务端压力和优化客户端体验,比如一个Web
站点,其中某些依赖的资源可能十年都不会变动,此时对这种资源进行缓存就非常合适。常说的缓存一般有两种,强缓存和协商缓存(弱缓存)
Http1.1
协议规范
强缓存 Cache-Control
主要使用的是Cache-control
响应头,如Cache-Control:max-age=3600
,当某个资源设置了该请求头后,再一个小时内再次缓存该资源(url
)时,不会再请求服务器,而是直接从缓存中读取
上面这张截图是知乎的某个页面加载的javascript
脚本,请求头中被设置了cache-control:max-age=31536000
,这个秒数换算下来是一年的时间,一年内我再次访问都不会再请求服务器,并且浏览器也在请求的状态码后标记了来自内存缓存(from memory cache
)
协商缓存 Etag
当请求资源时,服务器会返回特征值,名为etag
响应头,当强缓存的有效期过了后,浏览器会自动携带一个请求头名为If-None-Match
,值就是响应头返回的etag
的值。相当于会带着标识去访问服务器,这个资源目前该不该更新,具体是返回200
还是304
,就全看服务器。
- 返回
304
,告诉客户端该资源没有变过,继续使用,并且重新开始计算强缓存时间(如果有设置的话) - 返回
200
,告诉客户端资源可以删了,服务器会返回新的资源
搭建一个静态服务器动手验证
为了更方便的理解,这里用nginx
作简单的配置方便测试,为8080
端口如下配置,其中/Users/mongielee/cache-demo
改成自己的站点路径,站点内只需要两个文件,一个index.html
,一个main.js
server {
listen 8080;
server_name localhost;
location / {
root /Users/mongielee/cache-demo;
index index.html index.htm;
}
location ~ \.js$ {
root /Users/mongielee/cache-demo;
add_header Cache-Control max-age=10;
}
}
这里的配置主要是add_header Cache-Control max-age=10
,该配置为所有js
后缀的资源都添加了10s
都缓存时间,文件内容如下
启动或重启nginx
服务后,访问localhost:8080
可以看到响应头中携带着文件标识etag
和强缓存比标记cache-control
,此时十秒内再次访问main.js
资源,浏览器不会再发请求而是使用内存缓存
当10
秒过后再访问main.js
,浏览器就在请求头带上If-None-Match
标记,值为上一次请求的响应头中的etag
,带上If-None-Match
这一步浏览器会自动处理,此时返回的状态码就是304
,说明文件没有被修改,此时重新计算Cache-Control
的值
如果在二次请求前,服务器文件被修改,那么在强缓存过期后,协商缓存会返回200
状态码,原因是请求头的etag
值与服务器计算的不一致,下面图中,服务端新返回的etag
是xxx-1e
,而请求头带的是xx-1a
,说明文件被修改过
Http1.0
协议规范
之所以和1.1
有不同的内容,原因是1.0
并没有设计好,与Cache-Control
和etag
相对应的是Expires
和Last-Modified
强缓存Expires
使用该响应头返回客户端一个时间值,那么导致的问题就是如果客户端修改了时间,那么缓存直接就失效了,以及需要注意的地方是,当cache-control
和expires
同时设置时,会忽略掉expires
,使用cache-control
。在Expires
的指定时间内(客户端时间),都会从缓存中读取
协商缓存If-Modified-Since
当Expires
的时间过期后,再次访问资源请求头会带上一个If-Modified-Sice
,值就是上一次请求的响应头中Last-Modified
的值,服务器会进行文件的最后修改时间与请求头的If-Modified-Since
进行对比,如果发现时间一致则返回304
,若etag
和last-modified
同时设置则优先采用etag
,也就是1.1
的规范优先于1.0
这种方式的缺点是,精准只到秒级,如果一秒内对文件进行了两次(多次)修改,则结果就不会正确。下图中两次的时间比对一致,所以返回了304
应该优先采用1.1规范中的cache-control和etag
什么文件该设置缓存?
这个问题没有标准答案,完全看项目需求,但站点首页是绝对不能缓存的,否则永远无法加载版本迭代后的新内容,不过一般浏览器会禁止这种沙雕行为
完:)