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 分布式缓存中间件 方便实现缓存的分布式,集群, ...
 
随机推荐
- jQuery获取表格隐藏域与ajax请求数据结合显示详情
			
0.表格样式
 - 多表查询与pymysql
			
一.子查询 #1:子查询是将一个查询语句嵌套在另一个查询语句中. #2:内层查询语句的查询结果,可以为外层查询语句提供查询条件. #3:子查询中可以包含:IN.NOT IN.ANY.ALL.EXIST ...
 - CentOS6.9下安装 Pika 2.2.5(新增了拷贝安装版本的办法+对于PID的位置及数据库位置的理解)
			
一.环境准备 yum install -y snappy-devel protobuf-compiler protobuf-devel bzip2-devel zlib-devel bzip2 ...
 - 如果想从jenkins直接生成docker镜像,并推送到harbor中,最简单的脚本如何实现?
			
如果不考虑意外, 第一版最简单的构思如下: #!/usr/bin/env python # -*- coding: utf-8 -*- import getopt, sys import subpro ...
 - [BZOJ2631]tree 动态树lct
			
2631: tree Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 5171 Solved: 1754[Submit][Status][Discus ...
 - POJ 2407.Relatives-欧拉函数O(sqrt(n))
			
欧拉函数: 对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目. 对于一个正整数N的素数幂分解N=P1^q1*P2^q2*...*Pn^qn. Euler函数表达通式:euler(x)=x(1 ...
 - Ubuntu 14.04 安装JDK 8
			
1.安装JDK,参考 1.下载 JDK 8 从http://www.oracle.com/technetwork/java/javasebusiness/downloads/选择下载JDK的最新版本 ...
 - 使用es索引遇到的问题记录
			
1设置es索引的运行内存: 直接在启动文件里面改就好,启动命令是elasticsearch.bat,用notepad++编辑这个文件,里面添加这样的一行:SET ES_HEAP_SIZE=10g即可 ...
 - 2017中南大学暑期集训day1 : debug&STL-A
			
A - Surprising Strings 题意就是给你一个字符串,例如ZGBG,有一种称谓叫D-unique 这个字符串 在D=0时, 有三个子串 ZG GB BG,因为这三个都不同,也就是uni ...
 - hexo 的错误
			
错误如下 Connection to github.com closed by remote host. fatal: The remote end hung up unexpectedly erro ...