一、强缓存
第一次请求时,服务器把资源的过期时间通过响应头中的Expires和Cache-Control两个字段告诉浏览器,之后再请求这个资源的话,会判断有没有过期,没有过期就直接拿来用,不向服务器发起请求,这就是强缓存。
Cache-Control与Expires同时存在的话,Cache-Control的优先级高于Expires
(一)Cache-Control的几种模式
1、no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。
2、no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。
3、public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。
4、private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。
按照个人经验,Nginx一般都直接配置Cache-Control为no-cache,因为移动端特别是微信生态缓存是个很大问题,所以我一般都会直接设置为no-cache,不使用本地缓存,用协商缓存判断资源是否要重新请求加载。设置Cache-Control 为 no-cache 后,Expires自然也会失效,因为Cache-Control的优先级高于Expires
二、协商缓存
协商缓存利用(Last-Modified 、If-Modified-Since)和 (ETag 、If-None-Match)这两组方式来实现。(ETag 、If-None-Match)优先级高于(Last-Modified 、If-Modified-Since)
(一)Last-Modified 、If-Modified-Since
1、浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,会在 Respone 的 Header 的 Last-Modified 值设置一个修改时间,该资源最后修改的时间;
2、第二次请求的时候,在 Request 的 Header 上加上 If-Modified-Since,值为上次请求资源的 Last-Modified;
3、服务器收到 If-Modified-Since 与服务器文件的 Last-Modified 比对,
命中:无变化则返回 304,不返回资源。浏览器收到 304 使用本地缓存;不更新 Last-Modified;
不命中:有变化返回 200,重新更新 Last-Modified、返回 200、返回资源。
(二)ETag 、If-None-Match
1、浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,会在 Respone 的 Header 的 ETag 值设置一个标识,该标识为当前资源文件的一个唯一标识;
2、第二次请求的时候,在 Request 的 Header 上加上 If-None-Match,值为上次请求资源的 ETag;
3、服务器收到 If-None-Match 与服务器文件的 ETag 比对,
命中:一致则返回 304,代表资源无更新,故不返回资源。浏览器将会收到 304 使用本地缓存;
不命中:不一致返回 200,重新更新 ETag、返回 200、返回资源。
(三)为什么有Last-Modified 还要Etag呢?
1、一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
2、某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断;
3、某些服务器不能精确的得到文件的最后修改时间。
这时,利用Etag能够更加准确的控制缓存,因为Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符。Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag ,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。