浅谈http中的Cache-Control,cdn缓存加速失败的原因

摘要:
缓存控制在http中。有两个字段控制缓存开关:Pragma和cache control。当Pragma值为无缓存时,表示缓存已禁用。Expires值是GMT时间,表示缓存的有效时间。当缓存控制和过期同时出现时,应以缓存控制为准。缓存控制不仅可以用于响应,也可以用于请求。我们使用开发人员工具模拟带有缓存控制的请求:选中禁用缓存并刷新页面。您可以看到RequestHeaders中有一个字段Cache-Control:没有缓存。同时,缓存控制字段也可以在ResponseHeaders中找到。其值必须重新验证,由服务器设置。CDN制造商通常要求缓存控制值是公共的,以提高缓存命中率。

原文:

https://blog.csdn.net/u012375924/article/details/82806617

前言
我们用http访问时,会先发送一个请求,之后服务器返回一个应答,在Chrome的开发者工具(按F12或右击选择检查)中展现了整个过程:

第一部分General是概要,包含请求地址,请求方式,状态码,服务器地址以及Referrer 策略。
第二部分是应答头部,是服务器返回的。
第三部分是请求头部,是客户端发送的。

这次我们从两个角度来看看http的缓存:缓存控制和缓存校验。
缓存控制:控制缓存的开关,用于标识请求或访问中是否开启了缓存,使用了哪种缓存方式。
缓存校验:如何校验缓存,比如怎么定义缓存的有效期,怎么确保缓存是最新的。

缓存控制
在http中,控制缓存开关的字段有两个:Pragma 和 Cache-Control。

Pragma
Pragma有两个字段Pragma和Expires。Pragma的值为no-cache时,表示禁用缓存,Expires的值是一个GMT时间,表示该缓存的有效时间。
Pragma是旧产物,已经逐步抛弃,有些网站为了向下兼容还保留了这两个字段。如果一个报文中同时出现Pragma和Cache-Control时,以Pragma为准。同时出现Cache-Control和Expires时,以Cache-Control为准。即优先级从高到低是 Pragma -> Cache-Control -> Expires

Cache-Control
在介绍之前,先啰嗦两个容易忽视的地方:

符合缓存策略时,服务器不会发送新的资源,但不是说客户端和服务器就没有会话了,客户端还是会发请求到服务器的。
Cache-Control除了在响应中使用,在请求中也可以使用。我们用开发者工具来模拟下请求时带上Cache-Control:勾选Disable cache,刷新页面,可以看到Request Headers中有个字段Cache-Control: no-cache。

同时在Response Headers中也能到Cache-Control字段,它的值是must-revalidate,这是服务端设置的。
Cache-Control字段
在请求中使用Cache-Control 时,它可选的值有:

在响应中使用Cache-Control 时,它可选的值有:

no-store优先级最高
在Cache-Control 中,这些值可以自由组合,多个值如果冲突时,也是有优先级的,而no-store优先级最高。我们可以测试下:在nginx中做如下配置:

server {
listen 88;
root /opt/ms;
index index.php index.html index.htm index.nginx-debian.html;

location ~* ^.+.(css|js|txt|xml|swf|wav)$ {
add_header Cache-Control no-store;
add_header Cache-Control max-age=3600;
add_header Cache-Control public;
add_header Cache-Control only-if-cached;
add_header Cache-Control no-cache;
add_header Cache-Control must-revalidate;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
在/opt/ms下增加个文件type.css,内容如下:

a{
color: #000000;
}
a:focus,a:hover {
text-decoration: none;
color: #708090;
}
1
2
3
4
5
6
7
配置好之后,reload下nginx,在浏览器访问地址http://127.0.0.1:88/type.css,可以看到响应头部包含nginx配置中的字段:

重复刷新访问,会发现每次的状态码都是200,原因是no-store的优先级最高,本地不保存,每次都需要服务器发送资源。

public和private的选择
如果你用了CDN,你需要关注下这个值。CDN厂商一般会要求cache-control的值为public,提升缓存命中率。如果你的缓存命中率很低,而访问量很大的话,可以看下是不是设置了private,no-cache这类的值。如果定义了max-age,可以不用再定义public,它们的意义是一样的。

哪里设置Cache-Control
以LNMP的环境为例,一次响应经历的过程是:php-cgi解析代码并执行,将结果返回给nginx,如果nginx前面有反向代理,则会经过一次反向代理服务器,所以cache-control可能会在nginx,php-cgi,php代码,反向代理服务器这些地方地方设置。在php.ini中,有个参数是session.cache_limiter,需要注意下。在nginx中有个很常见的配置:

location ~* ^.+.(ico|gif|jpg|jpeg|png)$ {
expires 30d;
}
1
2
3
这个指令等同于cache-control: max-age=2592000,同时你会在响应头部看到一个etag字段,这是由于nginx默认开启,如果要关闭可以增加个配置etag off。这个etag就是我们接下要看的缓存校验字段。

缓存校验
在缓存中,我们需要一个机制来验证缓存是否有效。比如服务器的资源更新了,客户端需要及时刷新缓存;又或者客户端的资源过了有效期,但服务器上的资源还是旧的,此时并不需要重新发送。缓存校验就是用来解决这些问题的,在http 1.1 中,我们主要关注下Last-Modified 和 etag 这两个字段。

Last-Modified
服务端在返回资源时,会将该资源的最后更改时间通过Last-Modified字段返回给客户端。客户端下次请求时通过If-Modified-Since或者If-Unmodified-Since带上Last-Modified,服务端检查该时间是否与服务器的最后修改时间一致:如果一致,则返回304状态码,不返回资源;如果不一致则返回200和修改后的资源,并带上新的时间。

If-Modified-Since和If-Unmodified-Since的区别是:
If-Modified-Since:告诉服务器如果时间一致,返回状态码304
If-Unmodified-Since:告诉服务器如果时间不一致,返回状态码412

etag
单纯的以修改时间来判断还是有缺陷,比如文件的最后修改时间变了,但内容没变。对于这样的情况,我们可以使用etag来处理。
etag的方式是这样:服务器通过某个算法对资源进行计算,取得一串值(类似于文件的md5值),之后将该值通过etag返回给客户端,客户端下次请求时通过If-None-Match或If-Match带上该值,服务器对该值进行对比校验:如果一致则不要返回资源。
If-None-Match和If-Match的区别是:
If-None-Match:告诉服务器如果一致,返回状态码304,不一致则返回资源
If-Match:告诉服务器如果不一致,返回状态码412

总结
缓存开关是: pragma, cache-control。
缓存校验有:Expires,Last-Modified,etag。
从状态码的角度来看,它们的关系如下图:

cache-control的各个值关系如下图

————————————————
版权声明:本文为CSDN博主「小卡车7号」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012375924/java/article/details/82806617

免责声明:文章转载自《浅谈http中的Cache-Control,cdn缓存加速失败的原因》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇ShedLock日常使用记一次所有DELETE 请求全部404报错问题(put和get等其他请求均正常)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

MySQL的limit分页性能测试加优化

日常我们分页时会用到MySQL的limit字段去处理,那么使用limit时,有什么需要优化的地方吗?我们来做一个试验来看看limit的效率问题:环境:CentOS 6 & MySQL 5.71、建议一个实验表: collect(id[主键], title[varchar], info[text], vtype[tinyint]); Engine:...

FreeRTOS理解

列表的插入 初始化 插入步骤   在图3-1中我们看到寄存器xPSR被初始为0x01000000,其中bit24被置1,表示使用Thumb指令;寄存器PC被初始化为任务函数指针vTask_A,这样当某次任务切换后,任务A获得CPU控制权,任务函数vTask_A被出栈到PC寄存器,之后会执行任务A的代码;LR寄存器初始化为函数指针prvTaskExitErr...

RTT学习之线程管理

获得线程:rt_thread_t rt_thread_self(void);一 线程的创建和删除:rt_thread_create()创建的句柄,对应的删除rt_thread_delete(),注意线程的删除只是将线程的状态该为close,进入空闲任务才删除。rt_thread_init()函数对应的是rt_thread_detach()二 线程的就绪和挂...

web 阶段的一些简答题

1.jsp 9个隐含对象 2. jsp 4大域对象 3.mybatis 中 #{} %{ } 的区别于联系 4. Servlet容器默认是采用单实例多线程的方式处理多个请求的: 5.Cookie 与Session 的异同 6. 请描述对web 服务器的理解(Tomcat),请列举出tomcat7下的目录以及各个目录的作用 7. 请描述 servlet与st...

SmartStore.Net、NopCommerce 全局异常处理、依赖注入、代码研究

以下是本人最近对NopCommerce和SmartStore.net部分代码的研究和总结,主要集中于:依赖注入、异常处理、对象映射、系统缓存、日志这些方面,供大家参考。 NOP 3.8 /// <summary> /// 在NOP的运动环境中 进行组件、插件初始化、依赖注入、任务启动 /// </summary> /// <p...

微信小游戏 RES版本控制+缓存策略 (resplugin和ResSplitPlugin插件使用)

参考: RES版本控制 使用 AssetsManager 灵活定制微信小游戏的缓存策略 一、我们的目标 目标就是让玩家快速进入游戏,然后根据游戏的进度加载相应的资源,并可对资源进行版本控制、本地缓存、热更新。 如果美术改一张图或者策划修改一个配置文件就要发布版本再审核,就比较麻烦了。 所以方法3是我们要实现的目标。 翻看Egret的教程,提供了RES版本控...