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—缓存的更多相关文章

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

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

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

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

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

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

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

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

  5. [Java 缓存] Java Cache之 DCache的简单应用.

    前言 上次总结了下本地缓存Guava Cache的简单应用, 这次来继续说下项目中使用的DCache的简单使用. 这里分为几部分进行总结, 1)DCache介绍; 2)DCache配置及使用; 3)使 ...

  6. [原创]mybatis中整合ehcache缓存框架的使用

    mybatis整合ehcache缓存框架的使用 mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓 ...

  7. 探索ASP.NET MVC5系列之~~~5.缓存篇(页面缓存+二级缓存)

    其实任何资料里面的任何知识点都无所谓,都是不重要的,重要的是学习方法,自行摸索的过程(不妥之处欢迎指正) 汇总:http://www.cnblogs.com/dunitian/p/4822808.ht ...

  8. 深究标准IO的缓存

    前言 在最近看了APUE的标准IO部分之后感觉对标准IO的缓存太模糊,没有搞明白,APUE中关于缓存的部分一笔带过,没有深究缓存的实现原理,这样一本被吹上天的书为什么不讲透彻呢?今天早上爬起来赶紧找了 ...

  9. 缓存工厂之Redis缓存

    这几天没有按照计划分享技术博文,主要是去医院了,这里一想到在医院经历的种种,我真的有话要说:医院里的医务人员曾经被吹捧为美丽+和蔼+可亲的天使,在经受5天左右相互接触后不得不让感慨:遇见的有些人员在挂 ...

  10. .net 分布式架构之分布式缓存中间件

    开源git地址: http://git.oschina.net/chejiangyi/XXF.BaseService.DistributedCache 分布式缓存中间件  方便实现缓存的分布式,集群, ...

随机推荐

  1. DECODE 与CASE WHEN 的比较以及用法

    1.DECODE 只有Oracle 才有,其它数据库不支持; 2.CASE WHEN的用法, Oracle.SQL Server. MySQL 都支持; 3.DECODE 只能用做相等判断,但是可以配 ...

  2. 【bzoj2242】计算器

    #include<bits/stdc++.h> #define inf 1000000000 using namespace std; typedef long long ll; ?a:g ...

  3. Mark : Bootstrap fileInput控制预览页面上传、删除、详情按钮

    Bootstrap fileInput默认预览上传效果: 而我们可能想要的结果是: 这时候可以通过初始参数layoutTemplates来控制:

  4. AJAX--前后台交互

    注:ajax通过async参数决定是异步还是同步,false同步,true异步; 异步执行顺序是先执行后续动作,再执行success里代码; 同步是先执行success里代码,再执行后续代码; 验证: ...

  5. Linux命令之:tr

    1. 用途: tr,translate的简写,主要用于压缩重复字符,删除文件中的控制字符以及进行字符转换操作. 2. 语法: tr [OPTION]... SET1 [SET2] 3. 参数: -s: ...

  6. 举例说明如何使用【聚合数据】的API接口

    0 注册[聚合数据]的账号 登陆www.juhe.cn,如图,如果没有账号,注册一个(手机号或者邮箱注册),如果有直接登陆即可. 1 搜索所需的API接口 找到聚合数据主页,在搜索框输入你想搜索的AP ...

  7. CF 1003B Binary String Constructing 【构造/找规律/分类讨论】

    You are given three integers a, b and x. Your task is to construct a binary string s of length n=a+b ...

  8. scrapy详细数据流走向(个人总结)

    直接从数据流的角度来说比较容易理解: ·1.Spider创建一个初识url请求,把这个请求通过Engine转给Scheduler调度模块.然后Scheduler向Engine提供一个请求(这个请求是一 ...

  9. Struts2遇到Caused by Action class not found这类问题怎么解决

    刚才碰到个小坑,显示的错误是struts.xml找不到Action,明显不会有错的因为之前还是正常跑起来的,然后百度google搜了一通没解决,maven clean用了没反应还是照样报错. 最后在百 ...

  10. 安装virtualenvwrapper

    理解:virtualenv 和 virtualenvwrapper 是两种东西,前者可以单独使用,后者是管理前者的工具,尤其是当有多个 virtualenv(隔离环境时).所以下面的配置都是在为了使用 ...