由HTTP的缓存控制到缓存代理

1,596 阅读5分钟

浏览器缓存

  • memory cache是浏览器为了加快读取缓存的速度而作的优化

    读取速度:寄存器 > 高速cache > 内存 > 磁盘

image-20210530220917952

HTTP缓存控制

条件请求

  • 没有 If 开头的 条件请求 头字段时
1. 用HEAD请求获取该资源的Last-modified 或 ETag
2. 获取到的Last-modified 或 ETag与缓存的资源对比
3. 若资源发生了变化,那么就发送一次GET请求获取新的资源
   否则直接用缓存
  • HTTP定义了一系列的 If 开头的 条件请求 头字段,交由服务端来检验缓存是否过期
       客户端			      服务端
if-Modified-Since		Last-modified	        (弱检验器)	
if-None-Match			ETag			(强检验器)
  • ETag 全称 Entity Tag,资源的唯一标识符,用于解决Last-modified(单位秒)无法准确区分文件变化的问题

    • 强ETag要求资源在字节级别相同
    • 弱ETag要求资源在语义上相同即可(值前面有个 W/ 标记)
  • 图片来源

ETagAndIf-None-Match


两端缓存控制

  • 以前用Expires,缺点就是客户端这边可以修改本地时间,那就乱了呀,而现在Cache-Control: max-age=x,用相对响应报文创建的时间(Date头字段)

image-20210531231629713.png


  • 响应报文的头字段没有对缓存进行说明时,浏览器会采用一套 启发式算法来尽量缓存一段时间

    • 响应报文提供了Last-modified,但没有提供Cache-Control 或 Expires

      RFC建议:max-age =(Date - Last-modified)* 10%

    • 如果响应报文连Last-modified都没有呢,这个得看具体客户端是采用什么算法去缓存了

  • 响应报文的头字段 Cache-Control: max-age=0时,浏览器会不会缓存该资源呢 ?

    • 会,浏览器收到数据就会将其缓存起来,而内部有一套算法去清除,而max-age是浏览器清除缓存的参照物
  • 返回304和200的区别在于304不会携带实体数据,只是告诉浏览器Not Modified,让它去用缓存


应用

模式1: 不常变化的资源

  • 设置很长时间的强制缓存(时效性不强)
Cache-Control: max-age=31536000

模式2: 经常变化的资源

  • 设置使用前需要验证的强制缓存(时效性很强)
Cache-Control: no-cache
ETag: xxx
Last-modified: xxxx

模式1和2结合

  • 时效性不算太强,也不算太弱,来取个中
no-cache <=> max-age=0,must-revalidate
# 取中间
Cache-Control: max-age=600,must-revalidate
  • 很容易导致不同版本的资源组合在一起,导致报错
假设有三种资源:  index.html  index.js  index.css 存入浏览器缓存
	1. index.html的缓存有效时间先到期,被浏览器清除,而index.js index.css的缓存仍存在。
	2. 而此时浏览器请求到的新版本的index.html和旧版本的index.js和index.css组合很容易会报错

HTTP的代理服务

  • 代理一个是链路增长(成本),另一个交由它人处理(可信度)

client <=> proxy1 server <=> ... <=> proxyn server <=> origin server

  • X-Forwarded-ForVia 头字段经过代理节点就会添加上代理主机的信息

    • 前者添加 请求方的IP地址,后者添加 代理节点的Host
    • X-Real-IP === 仅有一个代理节点的 X-Forwarded-For 添加的IP地址
  • 图片来源

via


  • 客户端发送请求报文后,服务端会传来一个TCP报文表示 我将要传输的报文大小,请稍等

    步骤2 和 4的TCP报文作用修改为上述描述

  • 而服务端发送响应报文,请求方收到后会发送TCP报文表示收到该报文

    步骤5 和 7的TCP报文作用修改为上述描述

  • 四次挥手并没有规定是从客户端还是服务端开始,而三次握手是客户端主动发起的

    • 只不过通常都是客户端主动断开,所以看到是客户端先发送tcp,但服务端也可以主动断开(超时,短链接,节约资源)

image-20210531113936424


  • 因为通过X-Forwarded-For || X-IP || Via 都需要修改原始报文,添加上相应的头字段

    • 一方面加大了代理节点的工作量
    • 其次在SSL/TLS加密的情况下,不允许修改原始报文
  • 所以出现了 "代理协议"(The PROXY protocol)

image-20210531123545230


  • 反向代理的负载均衡算法有哪些 ?
    • 加权随机
    • 加权轮询
    • 最小连接法 || 最快连接法
    • 源地址哈希法

缓存代理

  • developer.mozilla.org/en-US/docs/…

  • 需要区分的是private cache 和 public cache

    HTTP协议的标准并没有规定默认使用private还是public,具体的看浏览器或代理服务器的实现,一般默认是private

HTTPCachtType

源服务器的缓存控制

  • no-transform

    • An intermediate cache or proxy cannot edit the response body,Content-Encoding,Content-Range,or Content-Type

      如:代理有时候会将缓存下来的数据做一些优化(图片生成png 、webp等几种格式),no-transform禁止这些变换

  • 仅在代理服务器生效的头字段,proxy-revalidate | s-maxage | no-transform

  • 图片来源

服务端代理缓存控制


客户端的缓存控制

  • 使用 only-if-cached 请求头字段,如果代理上没有缓存或缓存过期,返回504(GateWay Timeout)
请求报文中 max-age,max-stale,min-fresh 对`当前`缓存的有效时间的约束
    [min-fresh,)
    [start~max-age], start > 0
    [max-age,max-stale]
符合上述条件以及相应的 "Last-modified" and "ETag" 也符合的缓存返回

代理Cache-Control客户端缓存控制

Vary

  • vary主要用在缓存,用来告诉缓存代理此报文依据的是哪些请求头字段返回

    1. 返回带有Vary字段的响应报文给代理服务器,然后代理服务器将【w/ URL 
    and hash】作为key,该响应报文作为value存入缓存中
    * hash是根据vary字段的值,在该报文中提取出相应的值计算hash所得
    
    2. 当有新的请求访问代理服务器时,通过计算请求报文的相关头字段,得到相应的key,看缓存中是否存在
    	存在,则返回缓存
    	否则,向源服务器获取最新资源了
    
  • 图片来源

HTTPVary

参考