1

合理利用缓存
概述:本章主要讨论了两方面的内容。1. 浏览器缓存机制。 2. web实践中如何有效利用这些缓存
浏览器缓存机制

作为web开发人员经常遇到的问题之一就是我明明修复并且部署了这个BUG为什么线上有的用户还会出现这个问题呢?还有每次更新完我们都会说你清除缓存试试?为什么一定要清除缓存呢,可以肯定说绝大部分用户是不知道要清除缓存的!那我们能否不清除缓存,最新部署的文件能够马上就生效呢。答案是肯定的,这就需要我们花费一点时间了解一下缓存是怎么工作的。
我们可以简单的理解为缓存是为了减少网络带宽和优化用户体验而存在的。核心就是把缓存的内容保存在了本地,而不用每次都向服务端发送相同的请求,设想下每次都打开相同的页面,而在第一次打开的同时,将下载的js、css、图片等“保存”在了本地,而之后的请求每次都在本地读取,效率是不是高了很多。当我用浏览器打开一个网页可以发现浏览器加载页面资源的http请求返回的Status Code有以下常见的值304 Not Modified/200 OK (from disk cache)/ 200 OK。这些值代表着什么意思呢?其实浏览器就是依靠请求和响应中的的头信息来控制缓存的。下面我们来具体分析一下。
当我们第一次(或者ctrl+F5)打开百度,我们会发现加载jquery.js的http请求响应字段如下

clipboard.png

由于是第一次或者强制刷新打开的,所以浏览器会忽略缓存,直接向服务器发送请求加载资源,图中画框的那几个字段是与缓存相关的。它们的意义如下:

1. cache-control:max-age=315360000:它告诉浏览器这个资源的缓存时间为315360000秒(10年),那么浏览器就将这个文件保存到本地磁盘缓存起来,下次你再次打开百度时,只要是再10年内浏览器就不向服务器发送请求加载资源了,而是直接从缓存中加载。
2. expires:Fri, 06 Nov 2026 04:20:09 GMT:它告诉浏览器这个资源的有效期:现在-->2026年11月6号04:20:09,在这个时间内你打开百度浏览器就不向服务器发送请求加载资源了,而是直接从缓存中加载。

这个是不是与cache-control功能有点重合呢,是的!Expires是HTTP1.0的东西,而Cache-Control是HTTP1.1的,规定如果max-age和Expires同时存在,前者优先级高于后者。Cache-Control的参数可以设置很多值,譬如(参考浏览器缓存机制)。

3. Last-Modified: Mon, 07 Nov 2016 07:51:11 GMT:标示这个响应资源的最后修改时间。
4. ETag: 告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器觉得)

当我按下F5重新加载页面时会得到下面的http请求响应信息

clipboard.png

我们会发现浏览器是发送了一个http请求而不是我们之前说的在10年之内不发送请求,并且这个请求的响应是304,就是说当我按下F5时,浏览器忽略了上次请求返回的cache-control和expires字段的值,它是再次发送了一个获取资源的请求,但是这次http请求头部包含了两个新字段If-Modified-Since和If-None-Match(这两个字段的值就是上次请求资源响应中包含的Last-Modified和ETag的值),这就是问题所在,服务器检测到这两个字段做对应的响应如下:
If-Modified-Since:服务器收到请求后发现有头If-Modified-Since则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省加载时间与带宽),告知浏览器继续使用所保存的cache。
If-None-Match: 服务器收到请求后发现有If-None-Match则与被请求资源的相应校验串进行比对,决定返回200或304。

我们会发现这两个字段功能也有点重合,原因如下:
1) 次Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间。
2) 如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存。
3) 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形。
Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。

那现在就还剩下一个问题,就是当我按下F5时,浏览器为什么不是直接从本地缓存中加载文件而是发送了一个http请求呢?这个是就用户行为与浏览器对缓存的控制有关

clipboard.png

缓存总结如下
浏览器第一次请求:

clipboard.png

浏览器再次请求时:

clipboard.png

有效利用缓存
下面我们就来说说WEB资源文件的缓存时间设置为多少是全适的呢。

现在大部分网站都是每次更新部署时,只要有修改的文件都会重新生成一个名字(如:gulp打包[http://www.xxx.tv/dist/hr20170117/js/main-f3d7137ecb.js],HTML文件除外),相当于有更改的文件都有新的URL.针对这种情况,我们可以进行如下设置
  1. HTML文件可以设置为max-age为0,那么用户每次打开网页都会向服务器询问这个网页有没有更改,如果有更改用户就能够加载最新的文件。

  2. CSS/JS文件可以设置为30天或者1年。
    下面为对应的nginx配置
    location ~ .*.(js|css)?${

    expires 1M;

    }

  3. ~* .(?:manifest|appcache|html?|xml|json)$ {

expires -1;
}


spoondrift
26 声望1 粉丝