Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浏览器缓存策略 #8

Closed
lxfriday opened this issue Sep 20, 2019 · 14 comments
Closed

浏览器缓存策略 #8

lxfriday opened this issue Sep 20, 2019 · 14 comments
Labels
browser browser finished 已经完成

Comments

@lxfriday
Copy link
Owner

lxfriday commented Sep 20, 2019

总结成文章

欢迎关注我的微信公众号,定期更新精品文章~

image

@lxfriday lxfriday added the browser browser label Sep 20, 2019
@lxfriday
Copy link
Owner Author

mdn 相关文档

@lxfriday
Copy link
Owner Author

image

@lxfriday
Copy link
Owner Author

lxfriday commented Oct 16, 2019

http header 描述 强缓存 协商缓存
Pragma 老版本的本地缓存机制,http 1.0 及以下
Expires 在此时候之后,响应过期,时间是绝对时间,受本地时间影响 *
Cache-Control 强缓存策略 Cache-Control: public, max-age=31536000, must-revalidate max-age是相对时间 *
Last-ModifiedIf-Modified-Since 资源最后被更改的时间,精确到秒 *
ETagIf-None-Match 资源的标识值,用来唯一的标识一个资源 *

处理优先级

在本地 Cache-Control > ExpiresPragma 在不支持 Cache-Control 时生效。

如果本地缓存过期,则要依靠协商缓存

ETag > Last-Modified

强缓存的 http 状态码是 200 OK
协商缓存的 http 状态码是 304 Not Modified

@lxfriday
Copy link
Owner Author

Cache-Control

  • public 表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存
  • private 表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)。私有缓存可以缓存响应内容。
  • no-cache 在发布缓存副本之前,强制要求缓存把请求提交给原始服务器进行验证。
  • no-store 缓存不应存储有关客户端请求或服务器响应的任何内容。
  • max-age=<seconds> 设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。与Expires相反,时间是相对于请求的时间。
  • s-maxage=<seconds> 覆盖max-age或者Expires头,但是仅适用于共享缓存(比如各个代理),私有缓存会忽略它。
  • must-revalidate 一旦资源过期(比如已经超过max-age),在成功向原始服务器验证之前,缓存不能用该资源响应后续请求。
  • no-transform 不得对资源进行转换或转变。Content-EncodingContent-RangeContent-Type等HTTP头不能由代理修改。

禁止缓存

Cache-Control: no-cache, no-store, must-revalidate

缓存静态资源

Cache-Control:public, max-age=31536000

@lxfriday
Copy link
Owner Author

ETag

ETag HTTP响应头是资源的特定版本的标识符。这可以让缓存更高效,并节省带宽,因为如果内容没有改变,Web服务器不需要发送完整的响应。而如果内容发生了变化,使用ETag有助于防止资源的同时更新相互覆盖(“空中碰撞”)。

有两个作用

缓存未更改的资源

如果用户再次访问给定的URL(设有ETag字段),显示资源过期了且不可用,客户端就发送值为 ETagIf-None-Match header 字段

服务器将客户端的 ETag(作为If-None-Match字段的值一起发送)与其当前版本的资源的 ETag 进行比较,如果两个值匹配(即资源未更改),服务器将返回不带任何内容的 304 未修改状态,告诉客户端缓存版本可用(新鲜)。

避免“空中碰撞”

当编辑 MDN 时,当前的 Wiki 内容被散列,并在响应中放入Etag

ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4

将更改保存到 Wiki 页面(发布数据)时,POST 请求将包含有 ETag 值的 If-Match 头来检查是否为最新版本。

If-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

如果哈希值不匹配,则意味着文档已经被编辑,抛出 412 ( Precondition Failed) 前提条件失败错误。

@lxfriday
Copy link
Owner Author

lxfriday commented Oct 16, 2019

Pragma

http1.0 字段, 通常设置为Pragma:no-cache, 作用同 Cache-Control:no-cache 。强制要求缓存服务器在返回缓存的版本之前将请求提交到源头服务器进行验证。

浏览器勾选 Disable Cache 时,将会发送 Pragma:no-cache 给服务器

Pragma 优先级比 Expires 高,当同时有下面两个头时,浏览器仍然会发起请求,而不是使用本地的缓存。

Pragma: no-cache
Expires: xxx 

xxx 是一个没有过期的时间

@lxfriday
Copy link
Owner Author

lxfriday commented Oct 16, 2019

Age

Age 消息头里包含消息对象在缓存代理中存贮的时长,以秒为单位。.

Age 消息头的值通常接近于0。表示此消息对象刚刚从原始服务器获取不久;其他的值则是表示代理服务器当前的系统时间与此应答消息中的通用消息头 Date 的值之差。

Age: <delta-seconds>

age: 1135860

@lxfriday
Copy link
Owner Author

Date

Date 是一个通用首部,其中包含了报文创建的日期和时间。

指的是响应生成的时间. 请求经过代理服务器时, 返回的 Date 未必是最新的, 通常这个时候, 代理服务器将增加一个 Age 字段告知该资源已缓存了多久.

Date: Wed, 21 Oct 2015 07:28:00 GMT 

@lxfriday
Copy link
Owner Author

Vary

Vary 是一个HTTP响应头部信息,它决定了对于未来的一个请求头,应该用一个缓存的回复(response)还是向源服务器请求一个新的回复。它被服务器用来表明在 content negotiation algorithm(内容协商算法)中选择一个资源代表的时候应该使用哪些头部信息(headers).

对于服务器而言, 资源文件可能不止一个版本, 比如说压缩和未压缩, 针对不同的客户端, 通常需要返回不同的资源版本. 比如说老式的浏览器可能不支持解压缩, 这个时候, 就需要返回一个未压缩的版本; 对于新的浏览器, 支持压缩, 返回一个压缩的版本, 有利于节省带宽, 提升体验. 那么怎么区分这个版本呢, 这个时候就需要Vary了.

服务器通过指定 Vary: Accept-Encoding, 告知代理服务器, 对于这个资源, 需要缓存两个版本: 压缩和未压缩. 这样老式浏览器和新的浏览器, 通过代理, 就分别拿到了未压缩和压缩版本的资源, 避免了都拿同一个资源的尴尬.

Vary:Accept-Encoding,User-Agent

如上设置, 代理服务器将针对是否压缩和浏览器类型两个维度去缓存资源. 如此一来, 同一个url, 就能针对 PC 和 Mobile 返回不同的缓存内容.

@lxfriday
Copy link
Owner Author

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

可以设置 Cache-Control

Cache-Control: no-cache, no-store, must-revalidate 

也可以给资源增加版本号,这样可以很方便地控制什么时候加载最新资源

<link rel="stylesheet" type="text/css" href="../css/style.css?version=1.8.9"/>

@lxfriday
Copy link
Owner Author

小总结

浏览器第一次请求

image

再次请求时

image

@lxfriday
Copy link
Owner Author

lxfriday commented Oct 16, 2019

关于 memory cache 和 disk cache

image

来自 浏览器是根据什么决定「from disk cache」与「from memory cache」?

@lxfriday
Copy link
Owner Author

关于 Cache-control 的 public 和 private 的区别

ref Private vs Public in Cache-Control

image

@lxfriday lxfriday added the finished 已经完成 label Oct 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
browser browser finished 已经完成
Projects
None yet
Development

No branches or pull requests

1 participant