浏览器缓存机制(expires,cache-control,last-modified,etag)与Nginx配置调优

目录

  • 1. HTTP状态码
  • 2. last-modified
  • 3. etag
  • 4. cache-control
    • 4.1 浏览器对cache-control几种值的不同表现
      • 4.1.1 打开新窗口
      • 4.1.2 在原窗口按Enter键
      • 4.1.3 点击刷新按钮
      • 4.1.4 点击后退按钮
  • 5. expires
  • 6. 以上几种属性的优先级
  • 7. 可能出现的问题

浏览器缓存机制(expires,cache-control,last-modified,etag)与Nginx配置调优_第1张图片

缓存可以说是性能优化中简单高效的一种优化方式了, 一个优秀的缓存策略可以缩短网页请求资源的距离, 减少延迟, 并且由于缓存文件可以重复利用, 还可以减少带宽, 降低网络负荷. 对于浏览器缓存, 相信大家对它真的是又爱又恨. 一方面极大地提升了用户体验, 而另一方面有时会因为读取了缓存而展示了已经过期的数据, 而在开发过程中千方百计地想把缓存禁掉, 所以接下来本文就对浏览器的缓存机制进行详细的讲解, 彻底掌握浏览器的缓存规则, 妈妈再也不用担心缓存问题啦~

1. HTTP状态码

  • 200 (form memory cache) 不请求网络资源,从内存中读取资源,一般脚本、字体、图片会存在内存当中

  • 200 (form disk cache) 不请求网络资源,从磁盘中读取资源,一般非脚本会存在内存当中,如css等

  • 200 (1kb) 从服务器下载最新资源. (1kb即资源的大小)

  • 304 (1kb) 请求服务端发现资源没有更新,使用本地资源. (1kb即报文的大小)

以上是chrome在请求资源是最常见的几种http状态码

前两种200状态码是不需要浏览器请求服务器的, 直接从本地读取资源, 所以速度是最快的, 而304状态码也是缓存, 只不过需要浏览器先请求服务器, 这种是协商缓存

那么浏览器究竟在什么情景下会返回以上几种不同的状态码呢?

答案很简单, 在浏览器第一次访问某个URL时, 服务端会直接返回第三种200状态码, 返回内容是被请求的最新资源, 与此同时服务端可以在返回内容时主动设置Response Headers里的last-modified属性标记此资源在服务端最后被修改的时间, 还可以设置cache-control属性和etag属性以及expire属性, 浏览器就会根据返回的几个属性, 自行判断下次该如何请求资源, 那么下文将依次讲解这些属性的作用, 以及在什么情况会返回剩余的三种状态码.

2. last-modified

last-modified格式类似这样:

last-modified : Fri , 12 May 2006 18:53:33 GMT

客户端第二次请求此URL时,根据HTTP协议的规定,浏览器会向服务器发送if-modified-since报头,询问该时间之后文件是否有被修改过:

if-modified-since : Fri , 12 May 2006 18:53:33 GMT

如果服务器端的资源没有变化,则返回 304(Not Changed)状态码,内容为空,这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。

Nginx默认开启last modified特性, 也可以在nginx.conf中添加以下配置, 主动控制:

if_modified_since off|on;

3. etag

HTTP协议规格说明定义etag为“被请求变量的实体值”。另一种说法是,etag是一个可以与Web资源关联的记号(token)。典型的Web资源可以一个HTML文档,但也可能是JSON或XML文档。

服务器单独负责判断记号是什么及其含义,并在HTTP响应头中将其传送到客户端,以下是服务器端返回的格式:

etag:“50b1c1d4f775c61:df3”

客户端的查询更新格式是这样的:

if-none-match : W / “50b1c1d4f775c61:df3”

如果etag的值没有发生改变,则返回 304(Not Changed)状态码,这也和last-modified一样。etag在断点下载时会非常有用。

Nginx1.7.3及以上的版本默认开启Etag特性, 但是和Last-Modified一样, 可以主动配置:

etag off|on;

4. cache-control

cache-control 是最重要的规则。这个字段用于指定所有缓存机制在整个请求/响应链中必须服从的指令。这些指令指定用于阻止缓存对请求或响应造成不利干扰的行为。这些指令通常覆盖默认缓存算法。缓存指令是单向的,即请求中存在一个指令并不意味着响应中将存在同一个指令。

简单来说, 当同时存在last-modified以及etag还有cache-control这个3个属性时, cache-control的优先级是最高的

cache-control有以下几个值:

  • public 所有内容都将被缓存

  • private 内容只缓存到私有缓存中

  • no-cache 所有内容都不会被缓存

  • no-store 所有内容都不会被缓存到缓存或 Internet 临时文件中

  • must-revalidation/proxy-revalidation 如果缓存的内容失效,请求必须发送到服务器/代理以进行重新验证

  • max-age=xxx (xxx is numeric) 缓存的内容将在 xxx 秒后失效, 如果和Last-Modified一起使用时, 优先级更高

4.1 浏览器对cache-control几种值的不同表现

4.1.1 打开新窗口

public 会从缓存中读取资源, 也就是返回前两种200状态码

private, no-cache, no-store 都会重新访问服务器。

如果指定了max-age值,那么在此值内的时间里就不会重新访问服务器,例如:

cache-control: max-age=5(表示当访问此网页后的5秒内再次访问不会去服务器)

4.1.2 在原窗口按Enter键

public 会从缓存中读取资源, 也就是返回前两种200状态码

privatemust-revalidate 则只有第一次访问时会访问服务器,以后就不再访问。

no-cache, no-store 每次都会访问。

如果指定了max-age值,那么在此值内的时间里就不会重新访问服务器

4.1.3 点击刷新按钮

无论将cache-control设置为什么值,浏览器都会重新访问服务器

4.1.4 点击后退按钮

public、private、must-revalidate、max-age 都不会重新访问

no-cache 则每次都重复访问

cache-control是关于浏览器缓存的最重要的设置,因为它覆盖其他设置,比如 expires 和 last-modified。另外,由于浏览器的行为基本相同,这个属性是处理跨浏览器缓存问题的最有效的方法。

Nginx设置cache-control(例如设置max-age为30秒):

add_header Cache-Control "max-age=30";

PS: 分布式系统里多台机器间文件的last-modified必须保持一致,以免负载均衡到不同机器导致比对失败,分布式系统尽量关闭掉Etag(每台机器生成的etag都会不一样)

5. expires

Expires 头部字段提供一个日期和时间,响应在该日期和时间后被认为失效。失效的缓存条目通常不会被缓存(无论是代理缓存还是用户代理缓存)返回,除非首先通过原始服务器(或者拥有该实体的最新副本的中介缓存)验证。(注意:cache-control max-age 和 s-maxage 将覆盖 Expires 头部。)

Expires 属性接收以下格式的值:

Expires: Sun, 08 Nov 2009 03:37:26 GMT

如果查看内容时的日期在给定的日期之前,则认为该内容没有失效并从缓存中提取出来。反之,则认为该内容失效,缓存将采取一些措施。

6. 以上几种属性的优先级

last-modified, etag, cache-control, expires 被服务端同时设置时, 浏览器的下次请求会做出如下判断:

cache-controlexpires 控制浏览器是否从本地读取缓存, 并且cache-control会重写expires的规则。

例如cache-control设置了max-age, 浏览器则会先判断max-age,

如果cache-control没有设置max-age, 浏览器则会先判断expire, 再发送 Http 请求

服务器收到请求则会先判断资源的 last-modified,再判断 etag ,必须都没有过期,才能返回 304(Not Changed)状态码。

7. 可能出现的问题

前面只讲了几种属性同时被设置后, 浏览器和服务器判断的优先级, 还有一种情况(也是最常见的情况)也是需要我们去考虑的

那就是服务端只设置了last-modified 以及 etag, 并没有设置cache-control和expires属性

为什么说这种情况是最常见的? 仔细想想还真是那么回事, 因为nginx默认开启了last-modified和etag属性

如果一只后端汪正常地配置了生产环境, 并没有在缓存方面做一些配置, 那默认就是这种情况

这种情况下浏览器就不得不自行判断它应该将资源缓存多久。有些浏览器会将其缓存一天以上。

Google caching best practices guide 里提到: 浏览器会根据 last-modified 自行推算缓存时长。

Firefox 的推算方法是:

缓存时长 = (Date - last-modified) / 10

Chrome / Safari / IE 并没有公布他们的公式或算法。

此类文件的缓存时长通常取决于以下因素:

  • 浏览器开辟的缓存空间大小

  • 用户浏览过的站点数量和大小

  • 用户是否关闭了浏览器

也就是说当服务端只配置了last-modified 以及 etag, 没有配置cache-control和expires的时候, 除非用户手动点击刷新按钮, 否则浏览器每次都会从本地缓存中加载, 而且这个本地缓存的缓存时间也是未知的

这就导致了一个问题, 比如说你没有做任何缓存的配置, 却发现每次更新了网站的PHP, HTML, JS, CSS文件, 非得让用户手动点击刷新按钮才能显示更新内容, 这可不是我们想要的!(别问我怎么知道的)

所以,你如果不想关闭 last-modified,etag, 还不想浏览器从本地加载缓存资源,就应该显示地指定cache-control或expires

下面是我网站的nginx的缓存配置(仅供参考):

#设置css/js/图片等静态资源的expires为30天
location ~ .*\.(css|js|ico|png|gif|jpg|json|mp3|mp4|flv|swf)(.*) {
    expires 30d;
}
 
#设置index.html的max-age为30秒
location /index.html {
    add_header  Cache-Control "max-age=30";
}

讲到这里算是把浏览器的缓存策略全都弄清楚了, 而且一些可能出现的坑也说明了, 快去动手实践吧~

原文链接

Enjoy !!!

你可能感兴趣的:(无法分类啥都有,http头,浏览器缓存,nginx配置)