面试系列 - 什么是 HTTP 缓存?

267 阅读4分钟

前言

HTTP 属于客户缓存,我们常认为浏览器有一个缓存数据库,用来保留一些静态文件

当缓存数据库中有客户端需要的数据,如果数据未失效,客户端直接将数据拿出来使用。当缓存没有需要的数据时,客户端才会向服务端请求。

通常浏览器的缓存策略分为两种:强缓存和协商缓存

强制缓存

  • 对于强制缓存,服务器响应的 header 中会用 Expires 和 Cache-Control
  • 强缓存表示在缓存期间不需要请求,code 值为 200

Expires

Expires: Wed, 22 Oct 2018 08:41:00 GMT
  • Expires 的值为服务器返回数据的到期时间;如果再次请求的时间小于此时间,则直接使用缓存数据。 缺点:
  • Expires 受限于本地时间,如果修改了本地时间,可能会造成缓存失效。
  • 服务器时间和客户端时间可能有误差,也将导致缓存命中误差。

Cache-Control

Cache-Control: max-age=30

Cache-Control优先级高于 Expires。如上表示该资源在30秒后过期,需再次请求。

  • Cache-Control 有很多属性,不同属性代表不同意义。
    • private:客户端可以缓存
    • public:客户端、代理服务器都可以缓存
    • max-age=t:缓存内容将在 t 秒后失效
    • no-cache:需要使用协商缓存来验证缓存数据
    • no-store:所以内容都不缓存

现在一般使用 Cache-Control

协商缓存

又称对比缓存。客户会先从缓存数据库拿到一个缓存的标识,然后向服务端验证标识是否失效,如果没有失效 服务端会返回304,这样客户端可以直接去缓存数据库拿出数据,如果失效,服务端会返回新的数据。

对于协商缓存一共有两种方案:Last-ModifiedEtag

Last-Modified

Last-Modified:服务器告诉浏览器资源的最后修改时间

浏览器再次请求服务器时,请求头会包含字段,后面跟缓存中获得的最后修改时间

  • is-Modified-Since 字段
    • 从某个时间节点算起,是否文件被修改了。
    • 服务器收到后与请求资源最后修改时间进行对比,如果一致则返回 304
    • 不一致则响应整个资源
  • is-Unmodified-since 字段
    • 从某个时间节点算起,是否文件没有修改
    • 如果没有被修改:则开始传送文件;
    • 如果被修改则不传输,并返回 412 (预处理错误)

两者的区别是一个修改了才下载,一个是没修改才下载

缺点:

  • 服务器上的资源可能被修改,而实际内容根本没发生改变,但是会因为 Last-Modified 时间匹配不上而返回给客户端。
  • Last-Modified 只能以秒计时,如果在不可感知的时间内完成文件修改(一秒内),服务器还是会认为资源命中了,不会返回正确的资源。

Etag

服务器响应请求时,通过此字段告诉浏览器当前资源在服务器生成的唯一标识(生成规则由服务器决定)

  • if-None-Match字段:再次请求时,浏览器从缓存中获取标识,在请求头中包含此字段,服务器收到后做对比。
    • 相同则返回 304
    • 不同则说明资源有改动,则响应整个资源内容
    • ETag 优先级高于 Last-Modified
    • ETag 类似于文件指纹

缺点:

  • 但标识是通过计算出来的,会占用服务端计算的资源。

一般来说,现在会使用工具来打包代码,可以对文件名进行哈希处理,只有当代码修改后才会生成新的文件名。这样就可以当文件名修改时才去下载最新的代码文件

执行过程

  1. 浏览器地址栏写入 URL,回车后如果发现缓存中有这个文件,则不请求直接在缓存中拿数据。
  2. F5:浏览器发送请求并带上 if-modify-since ,服务器检查这个文件是否过期
  3. Ctrl + F5:将缓存中该文件删除,重新请求完整资源。

其他

强制缓存的优先级高于协商缓存,若两种缓存都存在,且强制缓存命中目标,则协商缓存不在验证标识

缓存的优点

  • 减少冗余的数据传递,节省宽带流量
  • 减少服务器负担,大大提高网站性能
  • 加快了客户端加载网页的速度(这也是 HTTP 缓存属于客户端缓存的原因)

参考

史上最全 HTTP 请求