聊聊http缓存

前言

  http缓存是WEB开发中比较重要的知识,缓存的作用是减少没必要的网络请求,提升页面加载速度,优化用户体验,减轻了服务器的压力,节省了带宽。我们必须掌握缓存的基本知识,才能利用好缓存,也能帮助我们解决开发中因客户端缓存导致资源不更新问题。

http缓存分为强制缓存和协议缓存

强制缓存:

  在资源文件没有过期前不会发送请求到服务器,直接使用本地缓存(磁盘、内存),强缓存通过Expires、Cache-Control 和 Pragma控制

1. Expires

  它是http1.0定义的字段,属性值是一个时间戳,当客户端再次请求该资源的时候,会把客户端时间与该时间戳进行对比,如果大于该时间戳则已过期,否则直接使用该缓存资源。
  Expires的一个缺点就是,返回的到期时间是服务器端的时间,这样存在一个问题,如果客户端的时间与服务器的时间相差很大,那么误差就很大,所以在HTTP 1.1版开始,使用Cache-Control: max-age=秒替代,如果Cache-Control与expires同时存在,Cache-Control生效。

2. Cache-Control

这是http1.1新增的字段,常用的属性值如有:

  • max-age:单位是秒,缓存时间计算的方式是距离发起的时间的秒数,超过间隔的秒数缓存失效
  • no-cache:不使用强缓存,需要与服务器验证缓存是否新鲜
  • no-store:禁止使用缓存(包括协商缓存),每次都向服务器请求最新的资源
  • private:专用于个人的缓存,中间代理、CDN 等不能缓存此响应
  • public:响应可以被中间代理、CDN 等缓存
  • must-revalidate:在缓存过期前可以使用,过期后必须向服务器验证

3. Pragma

  也是http1.0定义的字段,只有一个属性值:no-cache,作用和Cache-Control中的no-cache一样,优先级高于 cache-control 和 expires;三者同时出现时,优先级 pragma -> cache-control -> expires

协商缓存:

  当强缓存失效或者强缓存设置no-cache等不使用强缓存情况下,如果前一次请求的response header中有Last-Modified,ETag,浏览器就会在request header中携带If-Modified-Since(上一次请求返回的Last-Modified值),If-None-Match(上一次请求返回的ETag值),服务器根据这两个参数和服务资源对比看是否过期,如果没有过期服务器返回304,浏览器使用本地缓存,否则返回200,返回服务最新的资源文件。

1. Last-Modified / If-Modified-Since

  • 当浏览器第一次请求一个url时,服务器端的返回状态码为200,同时HTTP响应头会有一个Last-Modified标记着文件在服务器端最后被修改的时间。
  • 浏览器第二次请求上次请求过的url时,浏览器会在HTTP请求头添加一个If-Modified-Since的标记,用来询问服务器该时间之后文件是否被修改过。
  • 如果服务器端的资源没有变化,则自动返回304状态,使用浏览器缓存,从而保证了浏览器不会重复从服务器端获取资源,也保证了服务器有变化是,客户端能够及时得到最新的资源。

2. ETag / If-None-Match

  • 当浏览器第一次请求一个url时,服务器端的返回状态码为200,同时HTTP响应头会有一个ETag,存放着服务器端生成的一个序列值。
  • 浏览器第二次请求上次请求过的url时,浏览器会在HTTP请求头添加一个If-None-Match的标记,用来询问服务器该文件有没有被修改。

有Last-Modified为什么还要ETag? ETag 主要为了解决 Last-Modified 无法解决的一些问题:

  • 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET。
  • 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒)
  • 某些服务器不能精确的得到文件的最后修改时间

我们通过图示看下浏览器缓存流程:

1. 浏览器第一次请求

聊聊http缓存_第1张图片

2. 浏览器第二次请求

聊聊http缓存_第2张图片

问题:

  • 问题一

A:如果response header中没有Cache-Control等强缓存字段呢,浏览器怎么处理?
Q:如果没有强缓存字段浏览器会用 (当前时间-最后修改时间)*10% 计算出来的时间当成max-age,这个缓存时间不一定的,经常开发没问题但测试或上生产会出问题,当然这个计算公式不是所有浏览器都是这样的,因为没有明确指定缓存策略,浏览器厂商就按自己认为合适的策略进行缓存。

  • 问题二

A:如何解决入口页面缓存,比如微信缓存?
Q:入口页面应该加上Cache-Control:no-cache或者设置max-age一个比较短的时间,需要在http响应头中设置,不是html页面的meta标签,meta标签有的浏览器认有的浏览器不认。

  • 问题三

A:如何解决IE8,IE9 ajax get请求缓存问题?
Q:后台接口统一返回头中统一加上Cache-Control:no-cache,百度网盘,网易邮箱等后台接口返回的header都是no-cache或max-age=0的,当然前端框架加随机数等方式也能解决,比如jquery ajax的cache:false。

总结&实践

  1. 对于前端,入口页面使用no-cache或max-age设置为较短时间,js,css本身设置max-age为较长时间,引用js,css通过打包工具加hash版本号方式,这样浏览器只会请求修改的文件,没有修改的直接用缓存。
  2. 对于后端接口,最好都加上no-cache,这样在老旧的浏览器上不会出问题。
  3. 明确指定强制缓存字段和协商缓存字段,对不同资源制定合适的缓存策略,而不是依赖浏览器的默认规则有助于解决很多缓存兼容问题。

你可能感兴趣的:(缓存,前端,http)