声明:本人原创文章,详细内容已发布在我的微信个人技术公众号---网络技术修炼,公众号总结普及网络基础知识,包括基础原理、网络方案、开发经验和问题定位案例等,欢迎关注。

缓存概念

缓存处理请求步骤

缓存如果查询到某个请求已经有缓存,那么需要进一步检查该资源的新鲜度,根据新鲜度和请求中的字段综合评估是否要去服务端拉取新鲜的资源。

注意:

  • 创建响应时候要注意版本匹配,如果服务器响应和客户端请求的http版本不一致,要在缓存服务器做转换。
  • 缓存有通用的日志规范,常见的日志为Squid日志格式和网景的可扩展通用日志。
  • 缓存中过期的资源也不一定要删除,因为过期了也能用,删除一般采用特定算法,如LRU。

以http get为例缓存处理逻辑如下图所示。

服务端响应写入缓存

相关http字段

  • 缓存服务器如果不支持Range和Content-Range,那么不要缓存不完整的response。
  • 缓存服务器在未接收完一个Content-Range的content时候,不要给客户端该部分的应答。
  • 缓存服务器可以将多个Content-Range的content片段组合到一起应答给客户端。

缓存响应的创建

Vary

Vary 是一个HTTP响应头部信息,它决定了对于未来的一个请求头,应该使用一个缓存作为响应还是向源服务器请求一个新的响应。当响应中有vary字段的时候,缓存时候必须将vary字段一并缓存,下次请求的时候除了url外,还需要与vary缓存的字段完全一致才可以返回缓存内容。

例如,如果响应的 Vary 字段设置为 "Accept-Language",那么在缓存响应时,代理服务器和客户端应该按照请求中的 Accept-Language 字段来区分不同的响应。这意味着,如果一个客户端发出了两个不同的请求,其中一个请求的 Accept-Language 字段是 "en-US",另一个请求的 Accept-Language 字段是 "fr-FR",那么这两个请求应该获得不同的响应。

如果 Vary 字段为空,那么代理服务器和客户端可以缓存响应,并在任何请求中重用它。

内容协商除了vary,主要靠Accept来实现,Accept 字段,详见下表:

请求头字段

说明

响应头字段

Accept

告知服务器发送何种媒体类型

Content-Type

Accept-Language

告知服务器发送何种语言

Content-Language

Accept-Charset

告知服务器发送何种字符集

Content-Type

Accept-Encoding

告知服务器采用何种压缩方式

Content-Encoding

新鲜度

相关http字段

判断一个缓冲是否过期可以使用以下公式:

response_is_fresh=freshness_lifetime > current_age

其中freshness_lifetime为新鲜度声明周期,current_age为缓存已经生存的时间,这两个值都是使用的相对时间,后面有详细的计算方法。

注意:这个计算只能说明缓存中的内容是否新鲜,具体能否直接将该内容回复给客户端,还需要结合请求头中cache-control的max-age、max-stale、min-fresh字段进行综合判定。这个也比较好理解比如客户购买了一个苹果,吃的时候会看一下是否在保质期内,刚刚就是计算是否在保质期内,但不同人的处理可能不同,有的人发现过期两天也会吃,有的人发现临近过期就不吃了,请求中cache-control的max-age、max-stale、min-fresh字段就代表了不同处理方式的人。综上,关于缓存服务器对于一个存在的缓存资源是否能直接返回给客户端应该先计算freshness_lifetime - current_age,然后再综合请求中cache-control判断。

freshness_lifetime的计算

新鲜度生命时间(freshness_lifetime)表示资源从诞生到过期的相对时间(以秒为单位),其计算按照如下优先级依次计算,如果某个优先级的字段符合计算条件则跳过后面的计算:

推荐使用Date和Last-Modified 计算的缓存间隔时间除以10,即:

if ((last_modified > 0) && (date > 0) && (date - last_modified) > 0) {
return (date - last_modified) / 10;
}

current_age的计算

current_age表示资源从诞生到现在的相对时间( 以秒为单位),其参与current_age的计算的因素有:

  • Age字段表示实体从产生到现在以秒为单位经过多长时间了(多级缓存的场景,上一级缓存会填充该字段)。
  • Date字段表示报文内容在源服务器中诞生的时间。
  • 主机时间。

计算方法:

方法1: 用收到响应的时间减去Date字段的值。

用response_time表示收到响应的时间,用date_value表示Date字段的值,那么

current_age = response_time - date_value

但是,接收端和源服务器间很可能会有clock skew(时钟偏差),为了防止这种情况,将负数结果赋值为0,所以该计算方案最终为:

current_age = max(0, response_time - date_value)

方法2:逐跳计算。

接收端收到响应报文时的Age值等于上一跳节点中缓存的Age值加上传输时延。用previous_hop_age_value表示上一跳节点中缓存对的Age值,用response_delay表示传输时延,那么计算公式如下:

current_age = previous_hop_age_value + response_delay

respose_delay可以粗略地计算为得到响应时间减去发出请求的时间,这里你可能会问,为什么不要再除以二呢,因为HTTP对Age的计算策略是宁可多算也不肯少算的,多算顶多缓存新鲜时间变短,产生额外的新鲜度验证,但是少算的话,即使过期了,客户端还会把它当成新鲜的用。

response_delay = response_time - request_time

这种方法的好处是response_time和request_time都是本地的时间,不存在时间偏差。

综上所述,通常响应报文的计算会综合上述两种方法,取最大的一个。

#第一种计算方式
age_value_by_date = max(0, response_time - date_value)
#第二种计算方式
response_delay = response_time - request_time
age_value_by_hop = previous_hop_age_value + response_delay
#两种取大的
current_age = max(age_value_by_date, age_value_by_hop)

校验

相关http头

  • 条件验证通过服务器回复304 Not Modified,再验证实效返回200 ok。
  • 条件验证标签如果同时存在为“与”的逻辑关系,都满足才能返回304 Not Modified。

缓存控制

Cache-Control为http1.1上定义的缓存控制策略。

TODO:请求中优先级是什么,比如no-cache和only-if-cached如果同时存在,需要去服务端条件get吗?

其他

Pragma

Pragma: no-cache 含义与Cache-Control:no-cache相同,是为了兼容http 1.0版本的字段,当报文头同时出现Cache-Control和Pragma时候,Pragma被忽略。

Cache Control Extensions

详见:https://httpwg.org/specs/rfc7234.html#cache.control.extensions

Warning

此信息通常用于警告应用于消息有效负载的缓存操作或转换可能引入的错误。详细解释见:https://httpwg.org/specs/rfc7234.html#header.warning

Age

current_age的计算章节已经提到Age字段表示实体从产生到现在以秒为单位经过多长时间了源站服务器不会添加字段,但是缓存服务器会添加,也为多级缓存计算current_age提供了一个重要参数。详见:https://httpwg.org/specs/rfc7234.html#header.age

Via

Via 是一个通用首部,是由代理服务器添加的,适用于正向和反向代理,在请求和响应首部中均可出现。

参考文档

Hypertext Transfer Protocol (HTTP/1.1): Caching https://httpwg.org/specs/rfc7234.html

Hypertext Transfer Protocol -- HTTP/1.1 https://www.rfc-editor.org/rfc/rfc2616#section-14.44

Hypertext Transfer Protocol (HTTP/1.1): Range Requests https://www.rfc-editor.org/rfc/rfc7233

《http权威指南》

HTTP中缓存的使用期计算(Age Calculation)https://blog.csdn.net/sxh951026/article/details/77934463

rfc7234之http缓存的更多相关文章

  1. http2协议翻译(转)

    超文本传输协议版本 2 IETF HTTP2草案(draft-ietf-httpbis-http2-13) 摘要 本规范描述了一种优化的超文本传输协议(HTTP).HTTP/2通过引进报头字段压缩以及 ...

  2. 用node探究http缓存

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

  3. 用ASP.NET Core 2.1 建立规范的 REST API -- 缓存和并发

    本文所需的一些预备知识可以看这里: http://www.cnblogs.com/cgzl/p/9010978.html 和 http://www.cnblogs.com/cgzl/p/9019314 ...

  4. Web开发须知的浏览器内幕 缓存与存储篇(2)

    本文禁止转载,由UC浏览器内部出品. 3. HTTP Cache 综述 HTTP Cache是完全按照IETF规范实现的,最新的RFC规范地址是 https://tools.ietf.org/html ...

  5. 【转】用ASP.NET Core 2.1 建立规范的 REST API -- 缓存和并发

    原文链接:https://www.cnblogs.com/cgzl/p/9165388.html 本文所需的一些预备知识可以看这里: http://www.cnblogs.com/cgzl/p/901 ...

  6. REST API -- 缓存和并发

    REST API -- 缓存和并发 https://www.cnblogs.com/cgzl/p/9165388.html 本文所需的一些预备知识可以看这里: http://www.cnblogs.c ...

  7. 探究javascript对象和数组的异同,及函数变量缓存技巧

    javascript中最经典也最受非议的一句话就是:javascript中一切皆是对象.这篇重点要提到的,就是任何jser都不陌生的Object和Array. 有段时间曾经很诧异,到底两种数据类型用来 ...

  8. 哪种缓存效果高?开源一个简单的缓存组件j2cache

    背景 现在的web系统已经越来越多的应用缓存技术,而且缓存技术确实是能实足的增强系统性能的.我在项目中也开始接触一些缓存的需求. 开始简单的就用jvm(java托管内存)来做缓存,这样对于单个应用服务 ...

  9. ASP.NET Core 中间件之压缩、缓存

    前言 今天给大家介绍一下在 ASP.NET Core 日常开发中用的比较多的两个中间件,它们都是出自于微软的 ASP.NET 团队,他们分别是 Microsoft.AspNetCore.Respons ...

  10. ASP.NET Core 折腾笔记二:自己写个完整的Cache缓存类来支持.NET Core

    背景: 1:.NET Core 已经没System.Web,也木有了HttpRuntime.Cache,因此,该空间下Cache也木有了. 2:.NET Core 有新的Memory Cache提供, ...

随机推荐

  1. C#中静态字段声明时赋值与构造函数中赋值

    C#中静态字段是属于类的,访问的时候:用类名点成员名的方式. 赋值初始化的时候,可以在声明的时候赋值,也可以在静态构造函数中赋值. 如果在声明中.静态构造函数中都赋值,那么最终该成员的值,是取自哪一个 ...

  2. MySQL 分组排序,取第一条

    select t1.* from coal_installed_capacity t1where NOT EXISTS (select * from coal_installed_capacity t ...

  3. JS和PHP中能转为布尔false的值的对比

    实际开发中经常会使用到JS和PHP中的变量转布尔值进行条件判断,下面对两种语言中转布尔类型结果为false的值进行对比,加深记忆和方便引用. 除了下表列出项,其它的值均转成真值true . 转布尔值后 ...

  4. webservice学习随笔(二):通过cxf实现webservice

    一:基本概念(可跳过) Apache CXF 是一个开放源代码框架,提供了用于方便地构建和开发 Web 服务的可靠基础架构.它允许创建高性能和可扩展的服务,您可以将这样的服务部署在 Tomcat 和基 ...

  5. 如何通过C#/VB.NET从PowerPoint文档中提取图片

    PowerPoint是用于制作幻灯片(演示文稿)的应用软件,每张幻灯片中都可以包含文字.图形.图形.表格.声音和影像等多种信息.有时候我们发现在PPT里面有一些精美的图片,或者其他原因想要把PPT里面 ...

  6. 关于IDEA发出基于APR的本地库加载失败错误的解决------->求解决!

    问题描述 在没有使用Maven项目启动该Project时,Tomcat可以正常使用,但在这里会显示这样的错误: 这个错误,已经查了两天了,相关文件以及解决方法已经翻烂了,还没有解决,放出来集思广益一下 ...

  7. 面向对象分析与设计(V3)第一章:复杂性

    书名(中):面向对象分析与设计 书名(英):Object-Oriented Analysis and Design with Applications 作者:Grady Booch等 第一部分.概念 ...

  8. iText5实现Java生成PDF

    参考代码:https://github.com/youcong1996/study_simple_demo 参考博客:https://blog.csdn.net/weixin_37848710/art ...

  9. 多路复用IO:select poll epoll

    [电话面试]io多路复用专题面试 这个真猛 有人做了笔记:点这里 select Select(Max+1,&rset,null,null,null)是因为0~max是max+1. 过程: 将文 ...

  10. UI界面实现SSH登录服务器并执行命令监控

    一.通过paramiko实现SSH远程登录服务器.执行命令并返回信息: 二.通过wxpython实现UI化: 三.代码实现如下: 1)主程序MainUI #coding:utf8 #!/usr/bin ...