一 复习与目标

1 复习

  • 序章主要用WrieShark抓包HTTP报文
  • 复习了TCP协议
  • 讲述了TCP协议与HTTP之间的关系
  • HTTP1.1更新原因:HTTP1.0一次TCP连接只能发送一次HTTP报文等
  • HTTP2.0更新原因:HTTP的报头太大、多路复用问题等(HTTP2.0未来研究)

2 目标

  • 由于大家都有一定的基础(包括我),所以并不会照着书本一节一节地进行,所以这一节重点讲一下缓存相关的问题。
  • 缓存的好处
  • 缓存相关的状态码
  • 缓存相关的首部
  • 缓存的处理步骤

二 为什么要有缓存?

  • 减少冗余的数据传输
  • 缓解网络瓶颈
  • 降低对源服务器的要求
  • 降低距离时延

注:其实所有的好处都是不去重复获取相同文件带来的。

三 缓存存放在哪里?

  • 代理服务器(如:Nginx)
  • 浏览器(如:Chrome)

注:由于现在一般前后端分离开发,如:前端用Angular(Nginx),后端用Java(Tomcat),前端打包构建(代码压缩 编译优化 代码混淆等操作)成静态文件存放在Nginx中。本文主要以Chrome与Nginx的交互做例子。

四 缓存相关状态码

  • 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)示例

  • 服务器:Nginx
  • 客户端:Chrome
# 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项目打包生成项目结构

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和首部
  • 查询:查询本地副本是否可用,如果没有,则重新获取一份
  • 新鲜度检查:检查缓存副本是否新鲜,不新鲜则询问服务器是否有更新
  • 创建响应:用新的首部和以缓存的主体构建一条响应报文
  • 发送:通过网络把响应发回给客户端(可以是中间缓存服务器也可以使浏览器)
  • 日志(可选):创建一条日志文件来描述这个事务

参考:

HTTP协议探究(一):缓存的更多相关文章

  1. HTTP协议探究(六):H2帧详解和HTTP优化

    一 复习与目标 1 复习 HTTP1.1存在的问题 HTTP2.0要兼容HTTP1.1 HTTP2.0的重要概念 分帧层 二进制:流 消息 帧 流的状态.优先级和并发 流量控制 服务器推送 首部压缩 ...

  2. http协议与浏览器缓存

    http协议与浏览器缓存 F5刷新与在地址栏回车的区别 链接

  3. php 伪协议探究

    0x01序 PHP伪协议探究 php中支持的伪协议有下面这么多 file:// — 访问本地文件系统 http:// — 访问 HTTP(s) 网址 ftp:// — 访问 FTP(s) URLs p ...

  4. WebSocket协议探究(三):MQTT子协议

    一 复习和目标 1 复习 Nodejs实现WebSocket服务器 Netty实现WebSocket服务器(附带了源码分析) Js api实现WebSocket客户端 注:Nodejs使用的Socke ...

  5. WebSocket协议探究(序章)

    一 WebSocket协议基于HTTP和TCP协议 与往常一样,进入WebSocket协议学习之前,先进行WebSocket协议抓包,来一个第一印象. WebSocket能实现客户端和服务器间双向.基 ...

  6. socket协议下如何缓存图片--推荐EGOCache

    EGOCache是一个轻量级的缓存框架.用法简单方便,在现在的项目中,我就用到EGOCache来缓存下载过的照片和字符串. 有人可能会问到,缓存照片还需要用EGOCache吗?AFNetworking ...

  7. HTTP协议4之缓存--转

    HTTP协议提供了非常强大的缓存机制, 了解这些缓存机制,对提高网站的性能非常有帮助. 缓存的概念 缓存这个东西真的是无处不在, 有浏览器端的缓存, 有服务器端的缓存,有代理服务器的缓存, 有ASP. ...

  8. web基础-web工作原理,http协议,浏览器缓存

    1,web工作原理 2,http协议 3,浏览器缓存 4,cookie和session -------------------------------------------------------- ...

  9. 用node探究http缓存

    用node搞web服务和直接用tomcat.Apache做服务器不太一样, 很多工作都需要自己做.缓存策略也要自己选择,虽然有像koa-static,express.static这些东西可以用来管理静 ...

随机推荐

  1. .net core 修改 Identity/AspNetUsers 数据库

    众所周知,.net core有一套完整的用户管理功能.使用它就能实现用户的管理及登录登出功能.现在问题来了,我们有时候需要添加一些字段,该怎么办呢?当然是修改他呀.修改方法参考链接:https://m ...

  2. ccf 201803-2 碰撞的小球(Python)

    问题描述 数轴上有一条长度为L(L为偶数)的线段,左端点在原点,右端点在坐标L处.有n个不计体积的小球在线段上,开始时所有的小球都处在偶数坐标上,速度方向向右,速度大小为1单位长度每秒. 当小球到达线 ...

  3. SQL-W3School-基础:SQL SELECT 语句

    ylbtech-SQL-W3School-基础:SQL SELECT 语句 1.返回顶部 1. 本章讲解 SELECT 和 SELECT * 语句. SQL SELECT 语句 SELECT 语句用于 ...

  4. 18.flannel

    18.flannel docker有四种常用网络 bridge joined opended 直接共享使用节点的网络名称空间 none k8s网络通信: 容器间的通信: 同一个Pod内的多个容器之间通 ...

  5. Apache实现一台服务器上运行多个网站

    总共有三种方法:通过不同的IP地址 通过不同的域名 通过不同的端口号 (1).通过不同的IP地址实现 例如一台CentOS7有两个IP:192.168.5.101和192.168.5.103 [roo ...

  6. NuGet修改packages目录/迁移缓存文件夹

    如图,以下是NuGet默认配置 打开C:\Program Files (x86)\NuGet\Config目录的Microsoft.VisualStudio.Offline.config可以看见如下配 ...

  7. JAVA 基础编程练习题41 【程序 41 猴子分桃】

    41 [程序 41 猴子分桃] 题目:海滩上有一堆桃子,五只猴子来分.第一只猴子把这堆桃子凭据分为五份,多了一个,这只猴子把 多的一个扔入海中,拿走了一份.第二只猴子把剩下的桃子又平均分成五份,又多了 ...

  8. hadoop异常: java.io.EOFException: Unexpected end of input stream

    执行hadoop任务时报错: -- ::, INFO [main] org.apache.hadoop.mapred.MapTask: Processing --//app1@flume23_1000 ...

  9. 从字节跳动离职后,拿到探探、趣头条、爱奇艺、小红书、15家公司的 offer【转】

    前言 博主目前从事Android开发3年,前两年一直在抖音工作.我这篇文章并不是简单的描述一些面试中的题,或者总结一些Android的知识,而是想记录我整个的想法和准备的过程,以及一些心得体会,让大家 ...

  10. C#使用CUDA

    随着信息处理的爆炸增长,传统使用CPU计算已经无法满足计算作业增长的需求,GPU的出现为批量作业提供了新的契机.GPU计算拥有很类库,比如CUDA.OpenCL等,但是可以发现CUDA是其中相对比较成 ...