使用 HTTP 缓存机制提升系统性能
摘要
HTTP缓存机制定义在HTTP协议标准中,被现代浏览器广泛支持,同时也是一个用于提升基于Web的系统性能的广泛使用的工具。本文讨论如何使用HTTP缓存机制提升基于Web的系统,以及如何避免误用。同时也讨论了几种常见的应用场景。
一般性的缓存机制
抛开具体的技术实现,一般性来说在服务器-客户端模式下,缓存机制通常都是这么工作的,如图所示:
当客户端需要获取某个资源的时候,首先查看客户端本地缓存中是否存在此资源。如果缓存中不存在这个资源,则必须要从服务器端把资源拉到本地。如果存在,则还需要判断缓存的资源是否过期。如果没过期,则从缓存中直接获取资源,不需要再从服务器端获取。如果过期了,则必须从服务器端获取最新资源。还有一种很可能出现的情况是客户端不知道服务器端的资源更新了没有,即不知道缓存中的资源是否过期。这种情况下,客户端还是要向服务器端发请求的,不过在请求中附加了一些信息。这些信息用于服务器判断客户端缓存中的资源是否过期,例如最后修改日期。服务器端如果发现缓存的资源并未过期,那么只需要返回一个信号,告诉客户端从缓存获取即可,并不需要返回资源的内容。
HTTP协议定义的缓存机制
当Web浏览器向服务器请求资源时(如下图所示),服务器可以在响应中包含缓存相关的HTTP头(HTTP Header)。这些HTTP Header会告诉浏览器是否以及如何缓存资源。
关于缓存的HTTP Headers
下面列出的是关于缓存的HTTP Headers,它们有些是出现在响应(Response)中,有些在请求(Request)中。
| HTTP Header | 出现在 |
|----------------------|-----------------|
| Cache-Control | 响应 |
| Expires | 响应 |
| Last-Modified | 响应 |
| If-Modified-Since | 请求 |
| ETag | 响应 |
| If-None-Match | 请求 |
下面会一一介绍这些Header的用法,有一些是要配套使用的。
Cache-Control
在Chrome调试器中,可以在Response中找到Cache-Control,例如下图中的服务响应就包含一个Cache-Control头,其值为"public, max-age=30"
Cache-Control的值一般为 [public | private | no-cache, no-store ], [max-age=n] ([A | B] 表示可以从A和B中取一个),"max-age=n"表示n秒后资源失效。
public是指资源应该被缓存,并且中间经过的代理服务器(假如有的话)也应该缓存这个资源。隐含的意思是,其他用户可能也能分享这个资源的缓存。
private是指资源应该被缓存,但是只能被客户端的浏览器缓存。
no-cache, no-store是指示资源不应该被缓存。
max-age是指缓存多长时间,单位是秒。
下面举几个常用的例子:
Cache-Control : public, max-age=60
告诉浏览器,当前资源应该被缓存,同时也告诉代理服务器(假如有的话)也可以缓存这个资源。缓存应该在60秒后过期。
Cache-Control : private, max-age=60
告诉浏览器,当前资源应该被缓存,同时也告诉代理服务器(假如有的话)不要缓存这个资源。缓存应该在60秒后过期。
Cache-Control : no-cache, no-store
告诉浏览器以及代理服务器,不要缓存这个资源。
Expires
是相对于max-age的另一种指示过期时间的方式。max-age表示多少时间后过期,而Expires表示在某个日期时间点后过期。换种通俗的说法,max-age相当于说“保质期六个月”,而Expires是说“在此日期之前”饮用。
注意:如果max-age和Expires同时存在,应该以max-age为准。但是通常可以把两个都设置成一个时间点。例如下面的JavaScript代码所示:
// Set the max age to 1 year.
res.setHeader('Cache-Control', 'public, max-age=31536000');
// Set expire date to 1 year later.
var currentDate = new Date((new Date()).getTime() + 3600 * 1000 * 24 * 365);
res.setHeader('Expires', currentDate.toUTCString());
限制:max-age和Expires设置的缓存过期时间最多为一年(365天),如果多于这个值则浏览器有可能会忽略。
Last-Modified 和 If-Modified-Since
Last-Modified出现在响应中,告诉浏览器当前资源的最后修改时间,例如:
Last-Modified: Mon, 03 Jan 2011 17:45:57 GMT
而If-Modified-Since出现在下次请求中,询问服务器当前缓存的资源是否已经过期,例如:
If-Modified-Since: Mon, 03 Jan 2011 17:45:57 GMT
如果资源没有过期,则服务器应该返回304,不需要返回资源的内容。如果已过期,则服务器应该返回资源的内容到浏览器,并且返回200 HTTP状态码。
Last-Modified和If-Modified-Since配套使用,可以在保证不会误用缓存里的过期资源的前提下,减少服务器向浏览器发送的数据量,以及由于服务器在缓存未过期的情况下只需要返回304 HTTP状态码,而不需要返回整个资源的内容,也给了服务器优化的机会。
ETag 和 If-None-Match
Last-Modified 和 If-Modified-Since是用日期时间判断一个缓存的资源是否有效。ETag和If-None-Match则是用内容摘要作为判定的依据。内容摘要是指为一个资源的内容产生一串比较短的数字,当内容变化时,产生的数字串也会改变。内容摘要的算法有很多种,较常见的是SHA-1哈希算法、CRC32等。
ETag包含在服务器的响应中,为内容摘要。在下一次请求中,If-None-Match的值为上次的ETag的值。服务器根据If-None-Match的值(即内容摘要)判断缓存的资源是否有效。
304状态码
304状态码("Not Modified")表示资源(相对于缓存过的)没有被修改过。
检查请求与响应以及缓存工作情况
这里仅以Google Chrome为例,介绍如何检查请求与响应,以及检查浏览器缓存是否在发挥作用。其他的浏览器平台也是类似的。
打开Google Chrome,按F12,出现调试界面,切换到Network页。
你会看到很多请求,包括URL、方法、状态等等,注意到上图有一栏显示的是"(from cache)",已经用红框标出。这表示这些资源都是从缓存里获取的,没有经过服务器。清除Cache之后,看到的会是浏览器从服务器端获取资源,如下图所示:
点击其中的一项,显示出请求和响应的细节信息。
跟HTTP缓存相关的Header已经被红框标出,这里真正发挥作用Cache-Control和Expires,这两个让浏览器根本不用发请求。浏览器只要发请求就会产生一定的延时,因为即使服务器返回304这样简单的数据,在底层也还需要TCP/IP层的握手等各种操作,而且HTTP协议也会有额外开销。
应用场景
下面罗列了几种场景,并讨论如何设定缓存策略。
静态资源
对于那些不经常改变的静态资源,比如CSS、图片、动画等,应尽可能地利用缓存。因为这些资源通常很大而且几乎每个页面可能都会用到,缓存会大大提高系统效率。对于这些资源,响应中应该包含如下内容:
Cache-Control:public; max-age=31536000
Expires: Mon, 25 Jun 2013 21:31:12 GMT
max-age=31536000意味着31536000秒(也就是一年)后缓存失效。这里尤为注意不能设置成多于一年,因为RFC上限制了最大只能是一年,超过一年的情况不同的浏览器处理策略不同,有些直接就忽略了Cache-Control。
动态资源
对于动态内容,需要依据内容的实际情况,定义合适的max-age。例如对于SNS网络中的时间线通常可以设置成几秒。
私有内容
对于需要登录才能访问到资源,Cache-Control应该设置成private以禁止代理服务器缓存这些资源,否则会威胁信息安全。
禁用缓存
某些情况下需要禁止使用缓存,则应该把Cache-Control设置成"no-cache, no-store",如下所示。
Cache-Control:no-cache, no-store
使用 HTTP 缓存机制提升系统性能的更多相关文章
- 如何利用缓存机制实现JAVA类反射性能提升30倍
一次性能提高30倍的JAVA类反射性能优化实践 文章来源:宜信技术学院 & 宜信支付结算团队技术分享第4期-支付结算部支付研发团队高级工程师陶红<JAVA类反射技术&优化> ...
- MySQL缓存机制详解(一)
本文章拿来学习用||参考资料:http://www.2cto.com/database/201308/236361.html 对MySql查询缓存及SQL Server过程缓存的理解及总结 一.M ...
- ibatis的缓存机制
Cache 在特定硬件基础上(同时假设系统不存在设计上的缺漏和糟糕低效的SQL 语句)Cache往往是提升系统性能的最关键因素). 相对Hibernate 等封装较为严密的 ...
- MySQL缓存机制
对MySql查询缓存及SQL Server过程缓存的理解及总结 一.MySql的Query Cache 1.Query Cache MySQL Query Cache是用来缓存我们所执行的SELE ...
- 《MySQL面试小抄》查询缓存机制终面
<MySQL面试小抄>查询缓存机制终面 我是肥哥,一名不专业的面试官! 我是囧囧,一名积极找工作的小菜鸟! 囧囧表示:小白面试最怕的就是面试官问的知识点太笼统,自己无法快速定位到关键问题点 ...
- 【腾讯Bugly干货分享】Android ListView与RecyclerView对比浅析--缓存机制
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5811d3e3ab10c62013697408 作者:黄宁源 一,背景 Recy ...
- 理解 QEMU/KVM 和 Ceph(1):QEMU-KVM 和 Ceph RBD 的 缓存机制总结
本系列文章会总结 QEMU/KVM 和 Ceph 之间的整合: (1)QEMU-KVM 和 Ceph RBD 的 缓存机制总结 (2)QEMU 的 RBD 块驱动(block driver) (3)存 ...
- HTTP协议(缓存机制Cache)
HTTP的缓存 至于响应消息的实体,与请求消息的实体内容相似,这里只借绍下User-Agent头 User-Agent头域的内容包含发出请求的用户信息. Cache-Control头域(请求和应答通用 ...
- IOS缓存机制详解
资料均来自互联网,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任. 人魔七七:http://www.cnblogs.com/qiqibo/ 为什么要有缓存 应用需要 ...
随机推荐
- Black Box
http://poj.org/problem?id=1442 #include<cstdio> #include<algorithm> #include<queue> ...
- poj 2031Building a Space Station
http://poj.org/problem?id=2031 #include<cstdio> #include<cstring> #include<cmath> ...
- [flex & bison]编译器杂谈
flex与bison是编译器设计工具.这里的编译器为广义,其中包括一般的编译器.脚本解析器等,需要进行语言结构解析来得出意义的程序. 当我们需要用一个语言来设计一款编译器时,需要考虑太多设计重心外的东 ...
- 14.2 InnoDB and the ACID Model
14.2 InnoDB and the ACID Model ACID 模型是一组数据库设计原则,强调可靠性方面对于商业数据和关键人物. MySQL 包含组件比如InnoDB存储引擎坚持ACID 模型 ...
- Linux如何删除非空目录
这个问题很basic,不过还是困扰了我一段时间.(这里主要讨论的是命令行模式下) 我本来觉得应该使用命令 rmdir 但是发现它无法删除非空的目录. 后来发现了原来应该使用命令 rm -rf 目录名 ...
- 【6】JAVA---地址App小软件(QueryPanel.class)(表现层)
查找模块: 年龄可进行段查找. 其他的都是模糊匹配. 空格为无用字符,会屏蔽的(除年龄). (如果在年龄中输入空格,会出现异常,当时没想到这点,要防护这点很容易的,但因为在这个小软件的编写过程,我主要 ...
- gosslary
TM,技术手册(Technical Manual):商标(trademark)
- iOS 通过个推 推送原理
目前使用过的第三方推送很多,有极光, 友盟,个推等,现在主要针对个推,谈谈我对推送流程的理解. 在项目中,如果想要实现评论 推送功能 需要进行以下步骤: 1. 在用户登录的时候 通过 [GeTui ...
- JVM调优之jstack找出最耗cpu的线程并定位代码
jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多.下面我们来一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有 ...
- ButterKnife的使用
ButterKnife是一个Android View注入的库. 1.开始使用 1.1 配置Eclipse 在使用ButterKnife需要先配置一下Eclipse. 项目右键-Properties-J ...