一 复习与目标
1 复习
- 序章主要用WrieShark抓包HTTP报文
- 复习了TCP协议
- 讲述了TCP协议与HTTP之间的关系
- HTTP1.1更新缘由:HTTP1.0一次TCP链接只能发送一次HTTP报文等
- HTTP2.0更新缘由:HTTP的报头太大、多路复用问题等(HTTP2.0将来研究)
2 目标
- 因为你们都有必定的基础(包括我),因此并不会照着书本一节一节地进行,因此这一节重点讲一下缓存相关的问题。
- 缓存的好处
- 缓存相关的状态码
- 缓存相关的首部
- 缓存的处理步骤
二 为何要有缓存?
- 减小冗余的数据传输
- 缓解网络瓶颈
- 下降对源服务器的要求
- 下降距离时延
注:其实全部的好处都是不去重复获取相同文件带来的。css
三 缓存存放在哪里?
- 代理服务器(如:Nginx)
- 浏览器(如:Chrome)
注:因为如今通常先后端分离开发,如:前端用Angular(Nginx),后端用Java(Tomcat),前端打包构建(代码压缩 编译优化 代码混淆等操做)成静态文件存放在Nginx中。本文主要以Chrome与Nginx的交互作例子。html
四 缓存相关状态码
- 200:请求成功
- 304:请求资源服务器,返回资源未改动
- 200:过时时间内,浏览器直接获取硬盘内的缓存数据(from disk cache)
- 304:过时时间内,浏览器直接获取内存内的缓存数据(from memory cache)
五 缓存相关的HTTP首部
1 验证相关
(1)Etag示例
# 以Nginx生成的Etag值为例
# etag == last-modified的秒级Unix时间戳(16进制) - content-length(16进制)
# 响应首部
last-modified: Fri, 23 Nov 2018 03:47:36 GMT
content-length: 1408
etag: W/"5bf77858-580"
# 请求首部
if-none-match: W/"5bf77858-580"
if-modified-since: Fri, 23 Nov 2018 03:47:36 GMT
- Nginx收到请求后,比较Etag值是否修改,修改则返回新文件,状态码为200。
- 不然,返回状态吗304,告知浏览器从硬盘获取便可。
(2)强弱验证器
- 弱验证器:服务器对文档进行一些非实质性或不重要的修改时,不但愿已缓存的副本都失效。Etag表达:"5bf77858-580"。
- 强验证器:文档进行任何修改都会使得缓存的副本失效。Etag表达:W/"5bf77858-580"。
2 Cache-Control
(1)响应请求角度
no-cache |
无 |
强制向源服务器再次验证(返回200或者304) |
no-store |
无 |
不缓存请求或者响应的任何内容(返回200) |
max-age=[s] |
必须 |
响应的最大Age值 |
max-stale(=[s]) |
可省略 |
过时也照常接收 |
min-fresh=[s] |
必须 |
要求缓存服务器返回至少还未过指定时间的缓存资源 |
no-transform |
无 |
代理不可更改媒体类型 |
only-if-cached |
无 |
要求缓存服务器不从新加载响应,也不会再次确认资源有效性 |
public |
无 |
向任意方(代理或浏览器)提供响应的缓存 |
private |
可省略 |
仅向特定用户(浏览器)返回响应 |
no-cache |
无 |
强制向源服务器再次验证(返回200或者304) |
no-store |
无 |
不缓存请求或者响应的任何内容(返回200) |
no-transform |
无 |
代理不可更改媒体类型 |
must-revalidate |
无 |
代理可缓存可是必须再向源服务器进行确认(忽略请求的max-stale) |
proxy-revalidate |
无 |
全部缓存服务器在接收到客户端带有该指令的请求返回响应以前,必须再次验证缓存的有效性 |
max-age=[s] |
可省略 |
响应的最大Age值(忽略请求的Expires) |
s-maxage = [ 秒] |
必需 |
公共缓存服务器响应的最大Age值 |
(2)功能角度
- 什么是能够缓存的?响应(源服务器)决定
- public(共享缓存):响应消息可被任何缓存保存
- private(私有缓存):响应消息部分或者所有可被某个用户(如:浏览器)保存,但不可被共享缓存保存。
- no-cache(不缓存):指定一个或多个field-name不可缓存,即每次都须要去验证
- 什么能被缓存保存?响应决定
- no-store(不保存):防止敏感信息泄露,整个响应消息都不能保存。
- 对基本过时机制改进?响应或者请求决定
- Expires:指定过时时间。
- s-maxage(针对代理服务器):对共享(缓存来讲,s-maxage指定的值将会覆盖max-age缓存控制指令或Expires头域
- max-age(针对用户终端):优先级高于Expires,max-age未到时,不会去源服务器请求,而是从本地硬盘或内存中获取。
- min-fresh(保鲜时间):客户端想要响应至少在保鲜时间(min-fresh)内。
- max-stale(过时时间):客户端想要响应在保鲜时间内或过时不超过max-stale;若max-stale没有赋值,则客户端愿接受任意年龄的陈旧响应。
- 缓存重验证和加载控制?用户代理(响应或者请求)决定
- max-age=0:强迫重验证它所拥有的缓存项。
- only-if-cache:糟糕的网络链接下,客户端但愿缓存只返回缓存当前保存的响应,而且不须要经过源服务器对其缓存项进行从新加载或重验证。
- must-revalidate(针对代理服务器):若是基于源服务器的Expire或max-age值,已缓存的响应超过max-age时间,缓存必须每次重验证。
- proxy-revalidate(针对用户终端):相似于must-revalidate,但不适用于代理缓存。
(3)组合使用注意
- Cache-Control:max-age,s-maxage;时,那么代理使用s-maxage进行缓存,浏览器使用max-age进行缓存。
- Cache-Control:no-cache,max-age=60;时,max-age失效。
- Cache-Control:no-cache,no-store;时,no-cache失效。
- revalidate能与max-age可以配合使用,即max-age没过时,使用本地;过时则去从新获取。
- 单独使用revalidate时,浏览器或代理会有默认的max-age,不一样的浏览器该值不同(因此禁止这样使用)。
- 请必定要指定private public来指定容许缓存的代理或浏览器
(4)示例
# demo1
location / {
add_header Cache-Control max-age=30;
root /home/nginx/html;
index index.html;
}
# demo2
location / {
add_header Cache-Control private,max-age=30,proxy-revalidate;
root /home/nginx/html;
index index.html;
}
- 执行结果是同样的,max-age时间内,从本地获取,超出则访问服务器。
- 可是我强烈建议使用第二种,由于Chrome中两个的效果是相同的,鬼知道其余的浏览器会是怎样的体现。
六 浏览器的缓存处理流程
(1)处理流程
- HTTP响应判断是否可缓存?
- 确保Cache-Control值没有no-store或no-cache修饰
- 确保Cache-Control值有private或public修饰,通常默认值就是可缓存(响应建议显式加上)
- HTTP响应缓存多久?
- Cache-Control中的max-age(单位:秒)
- HTTP请求过程:
- 第一步:判断本地是否有缓存(max-age未过时),未过时直接本地获取
- 第二步:过时则首部带上验证信息(if-none-match:"响应的etag值" if-modified-since:"响应的last-modified值")
- 第三步:服务器验证本地文件与HTTP请求的Etag值与最后修改时间,若是相同直接返回304,让浏览器继续使用本地缓存,不然返回200,即返回新的文件和Etag值。(对应第七节)
(2)废弃和更新缓存的响应

- HTML 被标记为“no-cache”,这意味着浏览器在每次请求时都始终会从新验证文档,并在内容变化时获取最新版本。此外,在 HTML 标记内,您在 CSS 和 JavaScript 资产的网址中嵌入指纹:若是这些文件的内容发生变化,网页的 HTML 也会随之改变,并会下载 HTML 响应的新副本。
- 容许浏览器和中间缓存(例如 CDN)缓存 CSS,并将 CSS 设置为 1 年后到期。请注意,您能够放心地使用 1 年的“远期过时”,由于您在文件名中嵌入了文件的指纹:CSS 更新时网址也会随之变化。
- JavaScript 一样设置为 1 年后到期,但标记为 private,这或许是由于它包含的某些用户私人数据是 CDN 不该缓存的。
- 图像缓存时不包含版本或惟一指纹,并设置为1天后到期。
注:通常打包工具都具有给文件嵌入指纹,整个不须要担忧。前端
如:Angualr项目打包生成项目结构nginx
index.html
assets
img
logo.png
...
1.4f4fe517e78bb7b8a11d.js # 组件混淆文件
styles.2c73b882414fbdd03a9f.css
....
(3)缓存使用清单
- 使用一致的网址:若是您在不一样的网址上提供相同的内容,将会屡次获取和存储这些内容。
- 确保服务器提供验证令牌 (ETag):有了验证令牌,当服务器上的资源未发生变化时,就不须要传送相同的字节。(Nginx自带Etag计算)
- 肯定中间缓存能够缓存哪些资源:对全部用户的响应彻底相同的资源很是适合由 CDN 以及其余中间缓存进行缓存。(Nginx进行定制)
- 为每一个资源肯定最佳缓存周期:不一样的资源可能有不一样的更新要求。为每一个资源审核并肯定合适的 max-age。(Nginx进行定制)
- 肯定最适合您的网站的缓存层次结构:您能够经过为 HTML 文档组合使用包含内容指纹的资源网址和短期或 no-cache 周期,来控制客户端获取更新的速度。(Angular打包自动支持)
- 最大限度减小搅动:某些资源的更新比其余资源频繁。若是资源的特定部分会常常更新,能够考虑将其代码做为单独的文件提供。这样一来,每次获取更新时,其他内容能够从缓存获取,从而最大限度减小下载的内容大小。
七 中间代理的缓存处理流程
- 接收:读取抵达的请求报文
- 解析:报文解析,提取URL和首部
- 查询:查询本地副本是否可用,若是没有,则从新获取一份
- 新鲜度检查:检查缓存副本是否新鲜,不新鲜则询问服务器是否有更新
- 建立响应:用新的首部和以缓存的主体构建一条响应报文
- 发送:经过网络把响应发回给客户端(能够是中间缓存服务器也可使浏览器)
- 日志(可选):建立一条日志文件来描述这个事务
参考:web