您的位置 首页 java

3000字讲透HTTP缓存

概述

本文从 HTTP缓存策略 为入口,讲解HTTP缓存在浏览器的应用。

文章按 强缓存 协商缓存 启发式缓存 三个类别,进行深入剖析。

HTTP缓存策略

HTTP缓存分为三大策略:

  • 存储策略
  • 过期策略
  • 对比策略(也叫协商策略)

存储策略

存储策略,用于决定HTTP响应内容,是否可以缓存到客户端。

Cache-Control 头的 max-age no-cache no-store public private s-maxage ,使用存储策略,来指明资源文件是否可以被缓存。

过期策略

过期策略,用于决定客户端是否可以直接从本地缓存中读取文件数据,而不需要发起HTTP请求。

响应头包含 Cache-Control: public 的文件,虽然会被缓存,但不能明确当前文件是否在有效期内,所以需要其他字段做好“过期策略”。

强缓存的 Expires 字段,就是用 “过期策略” 定义缓存文件的有效期。借此,浏览器可判断是否需要发起HTTP请求。

响应头包含 Cache-Control: max-age=<seconds> 的文件,则包含存储策略和过期策略。

具体的策略应用,可以详细查阅下文的 Cache-Control 章节。

对比策略

将本地缓存文件的数据标识,发送到服务端进行验证,判断文件是否有效。这种策略,就叫对比策略,也叫协商策略。

对比策略,用于协商缓存场景,对应的字段是:

  • Last-Modified 和 If-Modified-Since
  • ETag 和 If-None-Match

例如:

ETag 用于存储缓存文件的哈希值。

浏览器需要判断当前缓存文件是否有效时,需要将 ETag 的值放入请求头 If-None-Match 字段,发送到服务端。

服务端接收到请求后,对比 If-None-Match 中的值与最新文件的值是否一致,来决定是否使用缓存。

当两个值一致时,则返回HTTP状态码304,告知浏览器,可使用本地缓存文件。

当两个值不一致时,则返回HTTP状态码200,并携带最新的文件返回给浏览器。

具体的策略应用,可以详细查阅下文的 协商缓存 章节。

小结

强缓存

强缓存通过字段 Expires Cache-Control 来控制本地缓存文件的有效期。

如果本地缓存有效,则浏览器不会发起HTTP请求。

在浏览器控制台 NetWork 中的体现为:

200 OK (from disk cache) 或者 200 OK (from memory cache)

释义

 200 OK (from disk cache)
200 OK (from memory cache)
  

强缓存的字段

字段

协议版本

缓存类型

响应头

请求头

Expires

HTTP1.0

强缓存

:o:️

:x:

Cache-Control

HTTP1.1

强缓存

:o:️

:o:️

HTTP1.1字段 优先级比 HTTP1.0字段高。

Expires

Expires 表示缓存的过期时间,时间代表的是 服务端的时间

如果本地时间小于 Expires 的时间,则在有效期内。浏览器会直接读取缓存,不会发起HTTP请求。

 Expires: Sun, 14 Jun 2020 02:50:57 GMT  

缺点

Expires 受限于本地时间,如果本地时间修改,则可能会导致缓存失效。

Cache-Control

Cache- Control 比较特殊,可以在 响应头 请求头 中使用。它通过提供不同的值,来定义缓存策略。

Cache-Control是所有缓存定义字段中,优先级最高的。

Cache-Control 字段取值

含义

存储策略

过期策略

响应头

请求头

max-age

缓存资源, 但是在指定时间(单位为秒)后缓存过期

:o:️

:o:️

:o:️

:o:️

no-cache

相当于 max-age:0,must-revalidate 即资源被缓存, 但是缓存立刻过期, 同时下次访问时强制验证资源有效性

:o:️

:o:️

:o:️

:o:️

no-store

请求和响应都不缓存

:o:️

:x:

:o:️

:o:️

public

资源将被客户端和代理服务器缓存

:o:️

:x:

:o:️

:x:

private

资源仅被客户端缓存, 代理服务器不缓存

:o:️

:x:

:o:️

:x:

s-maxage

依赖public设置, 覆盖max-age, 且只在代理服务器上有效

:o:️

:o:️

:o:️

:x:

must-revalidation / proxy-revalidation

如果缓存失效, 强制重新向服务器(或代理)发起验证(因为max-stale等字段可能改变缓存的失效时间)

:x:

:o:️

:o:️

:x:

max-stale

指定时间内, 即使缓存过时, 资源依然有效

:x:

:o:️

:x:

:o:️

min-fresh

缓存的资源至少要保持指定时间的新鲜期

:x:

:o:️

:x:

:o:️

only-if-cached

仅仅返回已经缓存的资源, 不访问网络, 若无缓存则返回504

:x:

:x:

:x:

:o:️

no-transform

强制要求代理服务器不要对资源进行转换, 禁止代理服务器对 Content-Encoding , Content-Range , Content-Type 字段的修改(因此代理的gzip压缩将不被允许)

:x:

:x:

:o:️

:o:️

释义

  • Cache-Control:max-age=31536000 距离请求发起的时间 + 31536000 秒之后,才会过期
  • Cache-Control: must-revalidate 缓存过期的任何情况下,都必须发起请求重新验证
  • Cache-Control: s-maxage=60 同max-age作用一样,距离请求发起的时间 + 60 秒之后,才会过期。
    只在代理服务器中生效(比如 CDN 缓存),
    s-maxage优先级高于max-age,只对 public 缓存有效 。设置了 s-maxage,没设置 public,代理服务器也可以缓存这个资源。
  • Cache-Control: no-store 所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存。
  • Cache-Control: no-cache 是否使用本地缓存都需要经过协商缓存来验证决定。使用 Etag 或者 Last-Modified 字段来控制缓存。
  • Cache-Control:max-age=31536000,max-stale=60 距离请求发起的时间 + 31536000 秒 + 60 秒之后,缓存才会失效。
    max-stale 表示最大容忍的过期时间,单位是秒。
  • Cache-Control:max-age=31536000, min-fresh=60 距离请求发起的时间 + 31536000 秒 – 60 秒之后,缓存才会失效。
    min-fresh 表示最小要留有N秒的新鲜度,单位是秒。

当max-age 与 max-stale 和 min-fresh 同时使用时, 它们的设置相互之间独立生效, 最为保守的 缓存 策略总是有效。

即哪个过期时间最早,就在这个过期时间后,发起资源请求,重新向服务端做验证。

协商缓存

当浏览器对某个资源的请求,没有命中强缓存,并在本地查找到缓存文件,则会发一个请求到服务器,验证本地缓存是否有效。

如果本地缓存文件有效,服务端响应请求,返回HTTP状态为: 304(Not Modified) , 不带消息主体。

如果本地缓存文件过期,服务端响应请求,返回HTTP状态为: 200 ,并携带资源实体数据。

协商缓存的字段

协商缓存字段分为两种:

  • Last-Modified 和 If-Modified-Since
  • ETag 和 If-None-Match

字段

Header 类型

协议版本

缓存类型

Last-Modified

Response(响应头)

HTTP1.0

协商缓存

If-Modified-Since

Request (请求头)

HTTP1.0

协商缓存

ETag

Response(响应头)

HTTP1.1

协商缓存

If-None-Match

Resquest(请求头)

HTTP1.1

协商缓存

HTTP1.1字段 优先级比 HTTP1.0字段高。

Last-Modified 和 If-Modified-Since

Last-Modified 表示本地文件的最后修改日期(精确到秒级)。

当浏览器发起资源请求时,会将文件的 Last-Modified 值,放入 If-Modified-Since 中,发送给服务端,询问该文件在该日期后,是否有更新。

如果在本地打开并修改缓存文件,则会导致Last-Modified日期被修改。

以下是例子:

  • 响应头
 Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT  
  • 请求头
 If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT  

缺点

 If-Modified-Since
  

注意点

  • Last-Modified 是服务端响应头 Response Headers 中的字段。
  • If-Modified-Since 是客户端请求头 Request Headers 中的字段。
  • If-Modified-Since 只可以用在 GET HEAD 请求中
  • 当与 If-None-Match 一同出现时, If-None-Match 的优先级更高。 If-Modified-Since 会被忽略掉,除非服务器不支持 If-None-Match

ETag 和 If-None-Match

ETag 像文件的指纹一样,每次内容一更改, ETag 值都会发生变化。

当浏览器发起资源请求时,会将上一次文件的 ETag 值,放入 If-None-Match 中,发送给服务端,询问该文件是否有更新。

ETag 值之间的比较采用的是 弱比较算法 ,即两个文件除了每个字节都相同外,内容一致也可以认为是相同的。例如,如果两个页面仅仅在页脚的生成时间有所不同,就可以认为二者是相同的。

举个例子:

 ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"  
ETag: W/"0815"  

其中, ‘W/’ (大小写敏感) 表示使用 弱验证器

注意点

ETag 是服务端响应头 Response Headers 中的字段。

If-None-Match 是客户端请求头 Request Headers 中的字段。

避免“空中碰撞”与 HTTP状态码412

空中碰撞,是指同时有多个人修改同个文件,产生竞态。

如果服务端接收每个人的保存请求,则会出现相互覆盖的状态。

所以,需要依靠ETag值,在保存前,做一些校验,以避免这种情况。

当需要修改或上传文件时,包含有 If-Match 头( ETag 值)的 POST 请求,会发送给服务端。

 If-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"  

如果服务端的文件哈希值与 If-Match 头的值不相等,则证明文件已经修改过。

这种情况下,服务端可以返回 HTTP状态码412 Precondition Failed (先决条件失败)表示客户端错误,拒绝处理请求。

启发式缓存

在资源请求的响应头中没有出现 Expires , Cache-Control: max-age , 或 Cache-Control:s-maxage 字段, 并且设置了 Last-Modified , 那么浏览器默认会采用一个 启发式的算法

启发式缓存的算法

取响应头的Date值 – Last-Modified值的结果的10%作为缓存时间。

详细可查看Caching in HTTP 中的介绍,笔者截取部分原文如下:

If none of Expires, Cache-Control: max-age, or Cache-Control: s- maxage (see section 14.9.3) appears in the response, and the response does not include other restrictions on caching, the cache MAY compute a freshness lifetime using a heuristic. The cache MUST attach Warning 113 to any response whose age is more than 24 hours if such warning has not already been added.

Also, if the response does have a Last-Modified time, the heuristic expiration value SHOULD be no more than some fraction of the interval since that time. A typical setting of this fraction might be 10%.

The calculation to determine if a response has expired is quite simple:

 response_is_fresh = (freshness_lifetime > current_age)  

巩固练习题

怎么让浏览器不缓存静态资源

 Cache-Control: no-cache, no-store, must-revalidate
  
 <link rel="stylesheet" type="text/css" href="../css/style.css?version=1.8.9"/>  
  • 部分浏览器支持在 HTML 中禁用缓存
 <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/>  

相同作用的请求头

  • Cache-Control: no-cache Cache-Control: max-age=0
    max-age=0 表示该资源已在0秒后过期,需要使用协商策略。因此,和 Cache-Control: no-cache 一样。

文章来源:智云一二三科技

文章标题:3000字讲透HTTP缓存

文章地址:https://www.zhihuclub.com/198100.shtml

关于作者: 智云科技

热门文章

网站地图