每天一点网站优化之:前端静态资源缓存

2,177 阅读6分钟

title: 每天一点网站优化之:前端静态资源缓存 date: 2019-06-18 17:00:00 tags: -JavaScript categories: JavaScript

关于静态资源缓存的配置,主要是后端开发的工作,前端开发的同学肯定都有一定的了解但并不深入。

今天我们就来全面的梳理一下静态资源缓存:

  • 静态资源缓存的定义是什么?
  • 静态资源缓存有哪些分类,分别应用在哪些场景?
  • 如何实现静态资源缓存,当前主流的方式是什么?

首先还是从一个小故事开始:小c同学是一名前端程序猿,负责公司门户网站的维护。这一天,他的大boss丢给他一张5M的大图,让他放到网站的首页。 这么大的资源,如果每次用户打开网站之后都要重新从服务器请求一遍,必然造成用户加载速度的减慢和带宽的浪费。 于是我们聪明的主人公想到了缓存的方法:把图片资源缓存到本地,下次需要这个资源的时候不必请求网络资源,直接从缓存中读取。

于是小c同学又开启了敲代码之旅。。。

缓存的分类

缓存存在于http的get请求中,浏览器可以根据request和response的header中字段的值、客户端时间等,智能地判断使用本地存储的内容还是服务端返回的内容。

  • 协商缓存304:用户发送的请求,发送到服务器后,由服务器判定是否从缓存中获取资源,如果文件没有变化,则从缓存中获取,如果文件有变动,从服务器中获取新的资源。
  • 强缓存200: 用户发送的请求,缓存时间过期之前,直接从客户端缓存中获取,不发送请求到服务器,不与服务器发生交互行为。

其中,强缓存又分为两种:磁盘缓存disk cache和内存缓存memory cache

  • disk cache:将资源缓存到磁盘中,等待下次访问时不需要重新下载资源,而直接从磁盘中获取,它的直接操作对象为CurlCacheManager。 它与memoryCache最大的区别在于,当退出进程时,内存中的数据会被清空,而磁盘的数据不会,所以,当下次再进入该进程时,该进程仍可以从diskCache中获得数据,而memoryCache则不行。
  • memory cache:将资源缓存到内存中,等待下次访问时不需要重新下载资源,而直接从内存中获取。Webkit早已支持memoryCache。 目前Webkit资源分成两类,一类是主资源,比如HTML页面,或者下载项,一类是派生资源,比如HTML页面中内嵌的图片或者脚本链接,分别对应代码中两个类:MainResourceLoader和SubresourceLoader。 虽然Webkit支持memoryCache,但是也只是针对派生资源,它对应的类为CachedResource,用于保存原始数据(比如CSS,JS等),以及解码过的图片数据。

发送http请求时,发生了什么

首次请求

  1. 客户端请求一个资源
  2. 服务端返回资源,并在response header中加上字段cache-control/expires,Last-Modified/ETag
  3. 客户端展现该页面,并将页面连同header中的字段存储 再次请求
  4. 如果有cache-control/expires字段,与客户端时间作对比,判断缓存是否过期, 如果没有过期,使用缓存资源,返回200(from disk cache)或200(from memory cache),如果已过期,向服务器发送请求
  5. 向服务器发送请求时,如果本地有Last-Modified/ETag字段,将上次请求的Last-Modified/Etag一起传递给服务器,与服务器资源作对比,判断上次请求之后资源是否有改变, 如果没有改变,返回304和一个空的响应体,否则返回200和新的资源

静态资源缓存的配置

与200缓存相关的字段

  • Expires:绝对过期时间 设置一个绝对过期时间Date字符串, 优先级比Cache-Control低, 同时设置Expires和Cache-Control则后者生效. 这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当客户端本地时间被修改以后,服务器与客户端时间偏差变大以后,就会导致缓存混乱。

  • Cache-Control:设置相对过期时间,以秒为单位,始终与客户端时间相比较。

    no-cache: 数据内容不能被缓存, 每次请求都重新访问服务器,若有max-age, 则缓存期间不访问服务器.

    no-store: 不仅不能缓存, 连暂存也不可以(即: 临时文件夹中不能暂存该资源)

    private(默认): 只能在浏览器中缓存, 只有在第一次请求的时候才访问服务器, 若有max-age, 则缓存期间不访问服务器

    public: 可以被任何缓存区缓存, 如: 浏览器、服务器、代理服务器等

    max-age: 相对过期时间, 即以秒为单位的缓存时间

与304缓存相关的字段:

  • Etag ETag将返回给浏览器一个资源ID(字符串), 如果有了新版本则正常发送并附上新ID, 否则返回304. ETag是为了解决Last-Modified只能精确到秒的问题,可以精确到毫秒。但是在服务器集群情况下, 必须保证每个分布式服务器返回相同的ETag.

  • Last-Modified: 该资源的最后修改时间, 在浏览器下一次请求资源时, 浏览器将先发送一个请求到服务器上, 并附上If-odified-Since头来说明浏览器所缓存资源的最后修改时间, 如果服务器发现没有修改, 则直接返回304(Not Modified)回应信息给浏览器(内容很少), 如果服务器对比时间发现修改了, 则照常返回所请求的资源.

静态资源缓存的实现

存储位置

资源缓存在用户的电脑上,浏览器目录中。mac os系统,chrome浏览器的缓存存储位置是:/Users/XXX/Library/Caches/Google/Chrome/Default/Cache,默认缓存文件没有后缀名,我们可以手动添加后缀名

image

实现304缓存

效果:

image

实现200缓存

在服务端的nginx中配置:

image

现象: 之前访问过图片资源,关闭浏览器(内存清空),再次打开页面 磁盘缓存:
image
在本页面刷新:
image

开发环境,不想使用缓存,如何实现

在服务器中配置 cache-control:no-store,禁止静态资源缓存

image

生产环境强制刷缓存策略

生产环境中,用户之前可能有200缓存,当资源有更改的时候,由于不能让用户手动清除缓存,可能出现在旧缓存有效期内,老用户显示缓存中内容的情况。 解决方法:把文件名和文件内容关联起来,比如js文件,每次修改文件内容后都关联的修改文件名称,强制用户使用新的文件,不使用缓存。

CDN回源 nginx相关配置 逐级优化字段 为何递进