HTTP—缓存
1. ETag
HTTP 1.1中引入了ETag来解决缓存的问题。ETag全称是Entity Tag,由服务端生成,服务端可以决定它的生成规则。如果根据文件内容生成散列值。那么条件请求将不会受到时间戳的改动造成带宽浪费。下面是根据内容生成散列值的方法:
var getHash = function(str) {
var shasum = crypto.createHash('sha1');
return shasum.update(str).digest('base64');
}
与If-Modified-Since/Last-Modified不同的是,ETag的请求和响应是If-None-Match/ETag。浏览器在收到带有ETag:'14-389247298365'字段的响应头后,会在后面的请求中将其设置在请求头中:If-None-Match: '14-389247298365'。服务器端收到带If-None-Match: '14-389247298365'的报头后,会进行如下判断来决定返回新的内容还是只响应一个304状态码让浏览器使用本地缓存版本:
var handle = function(req, res) {
fs.readFile(filename, function(err, file){
var hash = getHash(file);
var noneMatch = req['if-none-match'];
if (hash === noneMatch) {
res.writeHead(304, "Not Modified");
res.end();
} else {
res.setHeader("ETag", hash);
res.writeHead(200, "OK");
res.end(file);
}
})
}
2. Last-Modified
通常来说,如果请求头中不包含ETag,服务端会通过判断Last-Modified值来决定响应304状态码还是新的文件内容。Last-Modified顾名思义指的是文件的最后一次修改时间。与ETag一样,在浏览器首次访问站点后,服务端会在其响应头中设置一个Last-Modified的字段,它的值是一个UTC格式的时间字符串。随后,在浏览器对站点的第二次访问中,会在其请求头中设置一个If-Modified-Since,其值就是上一次返回的Last-Modified的值。服务器端会根据这个值是否与其本地文件的最后一次修改时间相同来判断是否使用缓存。代码如下:
var handle = function(req, res) {
fs.stat(filename, function(err, stat){
var lastModified = stat.mtime.toUTCString();
if (lastModified === req.headers['if-modified-since']) {
res.writeHead(304, "Not Modified");
res.end();
} else {
fs.readFile(filename, function(err, file){
var lastModified = stat.mtime.toUTCString();
res.setHeader("Last-Modified", lastModified);
res.writeHead(200, "OK");
res.end(file);
});
}
})
}
3. Expires 和 Cache-Control
以上两种的缓存判断都需要客户端向服务端先发送一个条件请求,根据返回来决定是否使用缓存。需要一定的时间开销和带宽。而实际上浏览器最先判断的是Expires 和 Cache-Control。在服务端相应里设置Expires 或 Cache-Control,浏览器会根据该值进行缓存。Expires是一个GMT格式的时间字符串。浏览器再接收到这个过期值后,只要本地还存在对应缓存文件,在到期时间之前它都不会再发起请求。但它的缺陷是浏览器与服务器之间的时间可能不一致,导致文件提前过期或已经过期却还没删除。
而Cache-Control恰恰解决了这个问题:
var handle = function(req, res) {
fs.readFile(filename, function(err, file){
res.setHeader("Cache-Control", "max-age=" + 10*365*24*60*60);
res.writeHead(200, "OK");
res.end(file);
});
}
上面的代码为Cache-Control设置了max-age值为10年,max-age会告诉浏览器文件多长时间后过期,进行倒计时式的计算。这样就可以避免客户端与服务器端时间不一致带来的问题了。此外Cache-Control还可以public、private、no-cache、no-store等更精细地控制缓存的选项。HTTP1.0时还不支持max-age,如今的服务端在模块的支持下多半同时对Expires 和 Cache-Control进行支持,如果浏览器中两个值都存在且同时被支持,max-age会覆盖Expires。
这两种方法虽然节省了带宽和请求时间,但其缺陷是当服务端的文件内容进行了更新时,无法通知客户端更新。因为浏览器是根据URL进行缓存的,所以我们一般在对静态资源使用缓存时也会对其设定版本号。使得客户端能请求到新的内容。一般更新机制有如下两种方式:
- 每次发布,web应用或静态资源的路径中附带对应的版本号:http://url.com/?v=20141216
- 每次发布,web应用或静态资源的路径中附带文件内容的hash码:http://url.com/?hash=sdasd4d
因为文件内容更新并不意味着新的版本。所以使用hash值得方式会更加妥当一些。
HTTP—缓存的更多相关文章
- 探究javascript对象和数组的异同,及函数变量缓存技巧
javascript中最经典也最受非议的一句话就是:javascript中一切皆是对象.这篇重点要提到的,就是任何jser都不陌生的Object和Array. 有段时间曾经很诧异,到底两种数据类型用来 ...
- 哪种缓存效果高?开源一个简单的缓存组件j2cache
背景 现在的web系统已经越来越多的应用缓存技术,而且缓存技术确实是能实足的增强系统性能的.我在项目中也开始接触一些缓存的需求. 开始简单的就用jvm(java托管内存)来做缓存,这样对于单个应用服务 ...
- ASP.NET Core 中间件之压缩、缓存
前言 今天给大家介绍一下在 ASP.NET Core 日常开发中用的比较多的两个中间件,它们都是出自于微软的 ASP.NET 团队,他们分别是 Microsoft.AspNetCore.Respons ...
- ASP.NET Core 折腾笔记二:自己写个完整的Cache缓存类来支持.NET Core
背景: 1:.NET Core 已经没System.Web,也木有了HttpRuntime.Cache,因此,该空间下Cache也木有了. 2:.NET Core 有新的Memory Cache提供, ...
- [Java 缓存] Java Cache之 DCache的简单应用.
前言 上次总结了下本地缓存Guava Cache的简单应用, 这次来继续说下项目中使用的DCache的简单使用. 这里分为几部分进行总结, 1)DCache介绍; 2)DCache配置及使用; 3)使 ...
- [原创]mybatis中整合ehcache缓存框架的使用
mybatis整合ehcache缓存框架的使用 mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓 ...
- 探索ASP.NET MVC5系列之~~~5.缓存篇(页面缓存+二级缓存)
其实任何资料里面的任何知识点都无所谓,都是不重要的,重要的是学习方法,自行摸索的过程(不妥之处欢迎指正) 汇总:http://www.cnblogs.com/dunitian/p/4822808.ht ...
- 深究标准IO的缓存
前言 在最近看了APUE的标准IO部分之后感觉对标准IO的缓存太模糊,没有搞明白,APUE中关于缓存的部分一笔带过,没有深究缓存的实现原理,这样一本被吹上天的书为什么不讲透彻呢?今天早上爬起来赶紧找了 ...
- 缓存工厂之Redis缓存
这几天没有按照计划分享技术博文,主要是去医院了,这里一想到在医院经历的种种,我真的有话要说:医院里的医务人员曾经被吹捧为美丽+和蔼+可亲的天使,在经受5天左右相互接触后不得不让感慨:遇见的有些人员在挂 ...
- .net 分布式架构之分布式缓存中间件
开源git地址: http://git.oschina.net/chejiangyi/XXF.BaseService.DistributedCache 分布式缓存中间件 方便实现缓存的分布式,集群, ...
随机推荐
- Linux内核态抢占机制分析【转】
转自:http://blog.csdn.net/yiyeguzhou100/article/details/53097665 目录(?)[-] 1非抢占式和可抢占式内核的区别 21 用户态抢占User ...
- json相关注解和序列化与反序列化
使用jackson进行序列化时,往往会遇到后台某个实体对象的属性为null,当序列化成json时对应的属性也为null,可以用以下的注解方式完成当属性为null时不参与序列化: @JsonSerial ...
- php扩展
swoole 命令行/php-fpm下实现的 多线程.异步.多种网络协议等 https://wiki.swoole.com/wiki/page/6.html 编译安装, 注意:需命令行运行,作为内部服 ...
- Linux下f命令配置
一.工具 f 的配置 使用 ========== ========== ========== ========== ========== ========== ==== 一.配置方法: 首先在lin ...
- 1.kafka的介绍
kafka是一种高可用,高吞吐量,基于zookeeper协调的分布式发布订阅消息系统. 消息中间件:生产者和消费者 举个例子: 生产者:做馒头,消费者:吃馒头,数据流:馒头 如果消费者宕机了,吃不下去 ...
- [ Python - 4 ] python 装饰器
装饰器有很多经典的使用场景,例如插入日志.性能测试.事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的. 装饰器有两种写法: 1. 装饰器不传参数 2. 装 ...
- 移动开发之css3实现背景渐变效果
前段时间由于手机项目需要实现一个背景渐变功能, 开始是想切个小背景图平铺下, 后来想到css3可以实现,如是用下面的代码就实现了. .sec_case_list li span{ backgro ...
- PostgreSQL9.6.3的REDIS测试
安装redis_fdwcd /usr/local/srcgit clone https://github.com/pg-redis-fdw/redis_fdw.gitcd redis_fdw/git ...
- Python项目在Jenkins中的自动化测试实践(语法检查、单元测试,coverage(代码覆盖率)、自动打包)
原始链接:http://blog.csdn.net/a464057216/article/details/52934077 requirments OS: Ubuntu 14.04+ Gitlab 8 ...
- BZOJ 1036: [ZJOI2008]树的统计Count-树链剖分(点权)(单点更新、路径节点最值、路径求和)模板,超级认真写了注释啊啊啊
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 23015 Solved: 9336[Submit ...