使用 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/ 为什么要有缓存 应用需要 ...
随机推荐
- DZY Loves Colors
CF #446C:http://codeforces.com/problemset/problem/444/C 题意:给你n个数,大小从1到n,然后又两种操作,1 a b c表示把区间a b 更新为c ...
- hdu 3400 Line belt
题意:给你两条线段AB,CD:然后给你在AB,CD上的速度P,Q,在其它部分的速度是R,然后求A到D的最短时间. 思路:用三分枚举从AB线段上离开的点,然后再用三分枚举在CD的上的点找到最优点,求距离 ...
- app开发历程————Android程序解析服务器端的JSON格式数据,显示在界面上
上一篇文章写的是服务器端利用Servlet 返回JSON字符串,本文主要是利用android客户端访问服务器端链接,解析JSON格式数据,放到相应的位置上. 首先,android程序的布局文件main ...
- Linux如何删除非空目录
这个问题很basic,不过还是困扰了我一段时间.(这里主要讨论的是命令行模式下) 我本来觉得应该使用命令 rmdir 但是发现它无法删除非空的目录. 后来发现了原来应该使用命令 rm -rf 目录名 ...
- 1036 : Trie图 (AC自动机)
题目大意: 输入 n 个目标单词和一个文本串,判断文本串中是否存在某些目标单词. 思路 赤裸裸的 AC自动机. 代码: #include<iostream> #include<cst ...
- UVA10557- XYZZY(spfa+设置次数上限)
题意:有N个房间,刚开始你位于1号房间,有100的能量值,你要到达N号房间,每两个房间之间有单向门相连接,你到达某个房间可以加上该房间的能量值, 如果你在未到达N号房间之前能量值耗尽,则死亡,否则胜利 ...
- E - Minimum Cost - POJ 2516(最小费)
题目大意:N个客户,M个供货商,K种商品,现在知道每个客户对每种商品的需求量,也知道每个供货商每种商品的持有量,和供货商把一种商品运送到每个客户的单位花费.现在想知道如果能满足所有客户的最小花费是多少 ...
- P - 奔小康赚大钱 - hdu 2255(带权值的匹配)
分析:这是一个KM的模板题,也就不多说了,KM最复杂的情况都能过,下面是没有优化过的代码: ****************************************************** ...
- java排序算法-选择排序
public class SelectionSort { private static void selectSortTest() { int[] sortArray = { 5, 2, 4, 1, ...
- 使用JDK自带缓存(Cache)实现Cookie自动登陆
自定义一个缓存类AdminCache package jw.admin.common; import jw.base.entity.Admin; import sun.security.util.Ca ...