淡人日记

落花无言,人淡如菊,书之岁华,其曰可读

静态文件缓存说明与配置

缓存说明

相关解释

在当前(2019/11月底)的网络环境下,用户通过网络来请求资源的效率低于通过从本地缓存中读取资源。因此在短期内不会改变的资源没有必要都向服务器发起请求。缓存策略就是为了改善客户端呈现的时间。

对于http请求的缓存机制来说,缓存策略体现在http的头部信息的字段上,而这些策略根据是否需要重新向服务器端发起请求可以分为强制缓存协商缓存两大类。

  • 强制缓存

    强缓存紧密联系着一个缓存时间期限,当浏览器请求资源的时候会查看缓存中的资源是否存在并且确定该缓存的资源是否过了“保质期”,若没有超过保质期则将取得缓存中的资源进行下一步处理

图片描述

  • 协商缓存

    商缓存无论如何都会和服务器交互,比较强缓存稍微要复杂一点,但是二者是相辅相成并且可以共同存在的,强缓存优先级较高,意味着请求一个资源时会先比较强缓存的字段,如果命中则不会再执行接下来的协商缓存的过程。

图片描述

强制缓存

与强缓存相关的HTTP header 的字段有两个 Expires以及Cache-Control

  • Expires

expires 字段规定了缓存的资源的过期时间,在此时间之前,缓存中的资源都是有效的,该字段的 value 是一个格林威治时间格式(GMT)的时间,即世界标准时间,js 通过 new Date().toUTCString()可得到,形如 Tue, 27 Feb 2018 06:37:48 GMT。他的缺点很明显,时间期限是服务器生成,存在着客户端和服务器的时间误差,固定时间,HTTP 1.0时的规范。相比较接下来介绍的cache-control优先级较低。

  • cache-control

此处参考资料https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cache-Control

Cache-Control类型 描述
private 仅客户端可以缓存,代理服务器不可以缓存
public 客户端和代理服务器都可缓存(代理包括CDN)。
max-age=xxx 缓存的内容将在 xxx 秒后失效
no-cache 需要使用协商缓存来验证缓存数据(后面介绍)
no-store 所有内容都不会缓存(强制缓存,协商缓存都不会触发)。

示例一:必须从服务器请求资源,发送如下header

Cache-Control: no-store

示例二:浏览器缓存资源

Cache-Control:public, max-age=31536000

协商缓存

协商缓存是通过客户端和服务端进行HTTP通信时,服务端客户端的缓存标识进行校对,通过返回头来确认客户端是否使用本地缓存。

  • Last-Modified 和 If-Modified-Since

第一次请求某一个资源时,由于一定不会走缓存,所以服务器端会在资源的响应头中加上一个形如Last-Modified:Mon, 26 Feb 2018 06:37:41 GMT的字段告诉客户端浏览器,这个资源上次最后修改的时间;刷新页面再次请求,这时候的协商缓存会在请求头中加上一个形如If-Modified-Since:Mon, 26 Feb 2018 06:37:41 GMT,让服务端去判断该资源有没有被修改过。

整个过程也很简单,最后的结果也很简短。如果服务端发现改变了资源,就伴着200的 statuscode 和新鲜的资源给到客户端,若是没有修改,304 Not Modified让客户端从缓存中取。

注意:由于此时间只精确到秒,因此该资源在同一秒发生修改,可以会出现意外情况

  • Etag 和 If-None-Match

同样,第一次客户端请求一个资源文件时,服务端随资源在响应头部中甩来一个字段 Etag ,形如ETag:W/"1823823287"该字段的值是该资源在服务器端的唯一标识,生成的Etag值的策略有服务端决定,总之是资源的一个唯一的标识。资源发生变化则该值也发生变化。下一次客户端请求同一个资源的时候,在请求头将这次得到的值放在请求头中一个叫 If-None-Match 的字段中甩给服务端。

整个过程也很简单,最后的结果也很简短。如果服务端发现改变了资源,就伴着200的 statuscode 和新鲜的资源给到客户端,若是没有修改,304 Not Modified让客户端从缓存中取。

上述两个方式中,Etag 和 If-None-Match的优先级要高于Last-Modified 和 If-Modified-Since,进而会衍生出一个思考,二者相比功能相同,但是表达形式决定了 Etag 解决了 Last-Modified 存在的一些问题,比如Last-Modified 是比较时间,精确到秒,若是毫秒级的改变则没法兼顾,存在着周期性更改的资源,然而有可能资源本身的内容并没有改变,那如果重新请求响应意义并不是那么的大。所以不难理解Etag具有高优先级有他的合理之处。

nginx缓存配置

对于前端资源来说我们希望.html文件使用协商缓存或者不使用缓存,其他资源文件.css .js 字体文件 图片文件使用强制缓存,nginx 配置如下

注意:在微信自带的浏览器环境中,协商缓存可能出现失效的情况

location ~* / {
  #.html文件不换车
  if ($request_filename ~* .*\.(?:htm|html)$) {
    add_header Cache-Control "no-store";
  }

  #.css .js 缓存七天
  if ($request_filename ~* .*\.(?:js|css)$) {
    expires 7d;
  }

  #.媒体文件缓存七天
  if ($request_filename ~* .*\.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm)$) {
    expires 7d;
  }
  #.字体文件
  if ($request_filename ~* .*\.(?:ttf|eot|otf|woff)$) {
    expires 7d;
  }
  
}

如上配置中.html文件通过添加返回头Cache-Control "no-store"不缓存文件。

目录