关于浏览器的缓存,有了Etag,last-etag last modifiedd还有必要存在吗

浏览器的总流程图
一步一步说缓存
朴素的静态服务器
设置缓存超时时间
html5 Application Cache
Last-Modified/If-Modified-Since
Etag/If-None-Match
什么是Etag
为什么有了Last-Modified还要Etag
Etag 的实现
迷之浏览器
在对页面的性能优化时,特别是移动端的优化,缓存是非常重要的一环。
浏览器缓存机制设置众多:html5 appcache,Expires,Cache-control,Last-Modified/If-Modified-Since,Etag/If-None-Match,max-age=0/no-cache...,
之前对某一个或几个特性了解一二,但是混在一起再加上浏览器的行为,就迷(meng)糊(bi)了.
下面从实现一个简单的静态服务器角度,一步一步说浏览器的缓存策略。
浏览器缓存总流程图
对http请求来说,客户端缓存分三类:
不发任何请求,直接从缓存中取数据,代表的特性有: Expires ,Cache-Control=和appcache
发请求确认是否新鲜,再决定是否返回304并从缓存中取数据 :代表的特性有:Last-Modified/If-Modified-Since,Etag/If-None-Match
直接发送请求, 没有缓存,代表的特性有:Cache-Control:max-age=0/no-cache
时间宝贵,以下是最终的流程图:
源码和流程图源文件在
一步一步说缓存
朴素的静态服务器
浏览的缓存的依据是server http response header , 为了实现对http response 的完全控制,用nodejs实现了一个简单的static 服务器,得益于nodejs简单高效的api,
不到60行就把一个可用的版本实现了:
可克隆代码,分支切换到step1, 进入根目录,执行 node app.js,浏览器里输入: header,返回正常,也没有用任何缓存。
服务器每次都要调用fs.readFile方法去读取硬盘上的文件的。当服务器的请求量一上涨,硬盘IO会成为性能瓶颈(设置了内存缓存除外)。
response header:
HTTP/1.1 200 OK
Content-Type: text/html
Date: Fri, 03 Jun :35 GMT
Connection: keep-alive
Transfer-Encoding: chunked
设置缓存超时时间
对于指定后缀文件和过期日期,为了保证可配置。建立一个config.js。
exports.Expires = {
fileMatch: /^(gif|png|jpg|js|css|html)$/ig,
maxAge: 60*60*24*365
为了把缓存这个职责独立出来,我们再新建一个cache.js,作为一个中间件处理request.
加上超期时间,代码如下
module.exports = function (request, response) {
var pathname = url.parse(request.url).pathname;
var ext = path.extname(pathname);
ext = ext ? ext.slice(1) : 'unknown';
if (ext.match(config.Expires.fileMatch)) {
var expires = new Date();
expires.setTime(expires.getTime() + config.Expires.maxAge * 1000);
response.setHeader(&Expires&, expires.toUTCString());
response.setHeader(&Cache-Control&, &max-age=& + config.Expires.maxAge);
这时我们刷新页面可以看到response header 变为这样了:
HTTP/1.1 200 OK
Expires: Sat, 03 Jun :23 GMT
Cache-Control: max-age=
Content-Type: text/html
Date: Fri, 03 Jun :23 GMT
Connection: keep-alive
Transfer-Encoding: chunked
多了expires,但这是第一次访问,流程和上面一样,还是需要从硬盘读文件,再response
再刷新页面,可以看到http header :
Request URL:http://127.0.0.1:8888/index.html
Request Method:GET
Status Code:200 OK (from cache)
Remote Address:127.0.0.1:8888
但是到这里遇到一个问题,并没有达到预期的效果,并没有从缓存读取
缓存并没有生效。
GET /index.html HTTP/1.1
Host: 127.0.0.1:8888
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0. Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,q=0.8
查看request header 发现 Cache-Control: max-age=0,浏览器强制不用缓存。
浏览器会针对的用户不同行为采用不同的缓存策略:
Chrome does something quite different: 'Cache-Control' is always set to 'max-age=0′, no matter if you press enter, f5 or ctrl+f5. Except if you start Chrome and enter the url and press enter.
其它的浏览器特性可以查看文末的【迷之浏览器】
所以添加文件entry.html,通过链接跳转的方式进入就可以看到cache的效果了。
浏览器在发送请求之前由于检测到Cache-Control和Expires(Cache-Control的优先级高于Expires,但有的浏览器不支持Cache-Control,这时采用Expires),
如果没有过期,则不会发送请求,而直接从缓存中读取文件。
Cache-Control与Expires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。
只不过Cache-Control的选择更多,设置更细致,如果同时设置的话,其优先级高于Expires。
代码详细可查看
html5 Application Cache
除了Expires 和Cache-Control 两个特性的缓存可以让browser完全不发请求的话,别忘了还有一个html5的新特性 Application Cache,
在我的另一篇文章中有简单的介绍.
同时在自己写的中,也用到了此特性,可离线查看,坑也比较多。
为了消除 expires cache-control 的影响,先注释掉这两行,并消除浏览器的缓存。
// response.setHeader(&Expires&, expires.toUTCString());
//response.setHeader(&Cache-Control&, &max-age=& + config.Expires.maxAge);
新增文件app.manifest,由于appcache 会缓存当前文件,我们可不指定缓存文件,只需输入CACHE MANIFEST,并在entry.html引用这个文件。
&html lang=&en& manifest=&app.manifest&&
在浏览器输入: ,已经在缓存文件了:
从浏览器的Resources标签也可以看到已缓存的文件:
这时再刷新浏览器,可以看到即使没有 Expires 和Cache-Control 也是 from cache ,
而index.html 由于没有加Expires ,Cache-Control和appcache 还是直接从服务器端取文件。
这时缓存的控制如下
本例子的源码为分支 step3:代码详细可查看
Last-Modified/If-Modified-Since
Last-Modified/If-Modified-Since。
Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向web服务器请求时带上头 If-Modified-Since,表示请求时间。web服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。
所以我们需要把 Cache-Control 设置的尽可能的短,让资源过期:
exports.Expires = {
fileMatch: /^(gif|png|jpg|js|css|html)$/ig,
同时需要识别出文件的最后修改时间,并返回给客户端,我们同时也要检测浏览器是否发送了If-Modified-Since请求头。如果发送而且跟文件的修改时间相同的话,我们返回304状态。
代码如下:
fs.stat(realPath, function (err, stat) {
var lastModified = stat.mtime.toUTCString();
var ifModifiedSince = &If-Modified-Since&.toLowerCase();
response.setHeader(&Last-Modified&, lastModified);
if (request.headers[ifModifiedSince] && lastModified == request.headers[ifModifiedSince]) {
response.writeHead(304, &Not Modified&);
response.end();
如果没有发送或者跟磁盘上的文件修改时间不相符合,则发送回磁盘上的最新文件。
同样我们清缓存,刷新两次就能看到效果如下:
服务器请求确认了文件是否新鲜,直接返回header, 网络负载特别较小:
这时我们的缓存控制流程图如下:
本例子的源码为分支 step4:代码详细可查看
除了有Last-Modified/If-Modified-Since组合,还有Etag/if-None-Match,
ETag ,全称Entity Tag.
Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定,具体下文中介绍)。
If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match (Etag的值)。
web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。
你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag(实体标识)呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存
有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形
在node 的后端框架express 中引用的是npm包,etag 支持根据传入的参数支持两种etag的方式:
一种是文件状态(大小,修改时间),另一种是文件内容的哈希值。
详情可相看
由上面的目的,也很容易想到怎么简单实现,这里我们对文件内容哈希得到Etag值。
哈希会用到node 中的Crypto模块 ,先引用var crypto = require('crypto');,并在响应时加上Etag:
var hash = crypto.createHash('md5').update(file).digest('base64');
response.setHeader(&Etag&, hash);
(request.headers['if-none-match'] && request.headers['if-none-match'] === hash)
// (request.headers[ifModifiedSince] && new Date(lastModified) &= new Date(request.headers[ifModifiedSince]))
response.writeHead(304, &Not Modified&);
response.end();
为了消除 Last-Modified/If-Modified-Since的影响,测试时可以先注释此 header,这里写的是 strong validator,详细可查看
第二次访问时,正常的返回304,并读取缓存
更改文件,etag发生不匹配,返回200
还有一部份功能特性,由于支持度不广(部份客户端不支持(chrome,firefox,缓存代理服务器)不支持,或主流服务器不支持,如nginx, Appache)没有特别的介绍。
到这里最终主要的浏程图已完毕,最终的流程图:
最终代码可查看
迷之浏览器
每个浏览器对用户行为(F5,Ctrl+F5,地址栏回车等)的处理都不一样,详细请查看
以下摘抄一段:
So I tried this for different browsers. Unfortunately it's specified nowhere what a browser has to send in which situation.
Internet Explorer 6 and 7 do both send only cache refresh hints on ctrl+F5. On ctrl+F5 they both send the header field 'Cache-Control' set to 'no-cache'.
Firefox 3 do send the header field 'Cache-Control' with the value 'max-age=0′ if the user press f5. If you press ctrl+f5 Firefox sends the 'Cache-Control' with 'no-cache' (hey it do the same as IE!) and send also a field 'Pragma' which is also set to 'no-cache'.
Firefox 2 does send the header field 'Cache-Control' with the value 'max-age=0′ if the user press f5. ctrl+f5 does not work.
Opera/9.62 does send 'Cache-Control' with the value 'max-age=0′ after f5 and ctrl+f5 does not work.
Safari 3.1.2 behaves like Opera above.
Chrome does something quite different: 'Cache-Control' is always set to 'max-age=0′, no matter if you press enter, f5 or ctrl+f5. Except if you start Chrome and enter the url and press enter.
这只是一篇原理或是规则性的文章,初看起来比较复杂,但现实应用可能只用到了很少的一部份特性就能达到较好的效果:
我们只需在打包的时候用gulp生成md5戳或时间戳,过期时间设置为10年,更新版本时更新戳,缓存策略简单高效。
关于缓存配置的实战这些问题,
比如,appcache,Expires/Cache-Control 都是不需发任何请求,适用于什么场景,怎么选择?
配置时,不是配置express,配的是nginx,怎么配置 ,下篇《详说浏览器缓存-实战篇》更新。
欢迎转载,但未经作者同意必须保留此段声明,且在文章页面保留此段声明。
阅读(...) 评论()Last-Modified和Expires针对浏览器,而ETag则与客户端无关,所以可适合REST架构中。两者都应用在浏览器端的区别是:Expires日期到达前,浏览器不会再发出新的请求,除非用户按浏览器的刷新,所以,Last-Modified和Expires基本是降低浏览器向服务器发出请求的次数,而ETag更侧重客户端和服务器之间联系。先谈Last-Modified和Expires,最新的Tomcat 7 将加入其容器中,这样,Java WEB也可以象Apache的Mod_expire模块一样对Http头部进行统一设置了,不过它只对响应文档类型进行统一设置判断,如text/html或text/image 或/css等等,如果想对个别URL输出的jsp进行定制就不行,urlrewrite据说是可以,但是要把URL在其配置文件再配置一下,麻烦,一旦jsp改动影响面大,还有一个问题就是web.xml配置了Tomcat 7容器的ExpireFilter,与容器耦合,移植性差(移植到Resin就不行了)。所以,我在jivejdon 4.2最新版本中,通过加入下面一段代码在服务器端对来自客户端的Last-Modified以及当前时间进行判断,如未过期,response.setStatus设为304,可以终止后面的各种Jsp界面计算,直接返回浏览器一个304的响应包,JSP页面也不会输出到客户端,将带宽节省给更加需要互动实时性的请求。再谈谈ETag,ETag定义:RFC2616(也就是HTTP/1.1)中没有说明ETag该是什么格式的,只要确保用双引号括起来就行了,所以你可以用文件的hash,甚至是直接用Last-Modified,以下是服务器端返回的格式:
ETag: "50b1c1d4f775c61:df3" 客户端向服务端发出的请求:If-None-Match: W/"50b1c1d4f775c61:df3"
这样,在J2EE/JavaEE服务器端,我们判断如果ETag没改变也是返回状态304,起到类似Last-Modified和Expires效果。与Last-Modified和Expires区别是:如果过了Expires日期,服务器肯定会再次发出JSP完整响应;或者用户强按浏览器的刷新按钮,服务器也必须响应,apache等静态页面输出也是这样,但是这时动态页面就发挥了作用,如果JSP涉及的业务领域模型还是没有更新,和原来一样,那么就不必再将动态页面输出了(浏览器客户端已有一份),从Etag中获取上次设置的领域模型对象修改日期,和现在内存中领域模型(In-memory Model)修改日期进行比较,如果修改日期一致,表示领域模型没有被更新过,那么返回响应包304,浏览器将继续用本地的该页面,再次节省了带宽传输。通过上述Expire和Etag两次,可以大大降低服务器的响应负载,如果你的应用不是状态集中修改和实时输出,而是分散修改然后分发,如个人空间 个人博客(每个人只是修改它们自己的状态,不影响全局)或QQ类似个人工具,那么采取这样的方法效果非常明显,实际就是一种动态页面静态化技术,但比通常事先进行页面静态化要灵活强大。InfoQ的那篇:还用MD5计算放入其中,Md5计算稍微复杂点,负载大了点,有的人结合Hibernate或数据库触发器来判断数据库数据是否更新,以决定Etag的更新,这将表现层和持久层耦合在一起,由于JiveJdon采取的是MDD/DDD模型驱动架构,表现层的Etag更新是根据中间业务层的模型对象修改日期来决定,不涉及数据库层,而且起到服务器的更新和http的Etag更新一致的效果,在松耦合设计和性能上取得综合平衡。代码如下:public static boolean checkHeaderCache(long adddays, long modelLastModifiedDate, HttpServletRequest request, HttpServletResponse response) {
// com.jdon.jivejdon.presentation.filter.ExpiresFilter
request.setAttribute("myExpire", adddays);
// convert seconds to ms.
long adddaysM = adddays * 1000;
long header = request.getDateHeader("If-Modified-Since");
long now = System.currentTimeMillis();
if (header > 0 && adddaysM > 0) {
if (modelLastModifiedDate > header) {
// adddays = 0; // reset
response.setStatus(HttpServletResponse.SC_OK);
if (header + adddaysM > now) {
// during the period happend modified
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
// if over expire data, see the E
// ETags if ETags no any modified
String previousToken = request.getHeader("If-None-Match");
if (previousToken != null && previousToken.equals(Long.toString(modelLastModifiedDate))) {
// not modified
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
// if th model has modified , setup the new modified date
response.setHeader("ETag", Long.toString(modelLastModifiedDate));
setRespHeaderCache(adddays, request, response);
} public static boolean setRespHeaderCache(long adddays, HttpServletRequest request, HttpServletResponse response) {
request.setAttribute("myExpire", adddays);
long adddaysM = adddays * 1000;
String maxAgeDirective = "max-age=" +
response.setHeader("Cache-Control", maxAgeDirective);
response.setStatus(HttpServletResponse.SC_OK);
response.addDateHeader("Last-Modified", System.currentTimeMillis());
response.addDateHeader("Expires", System.currentTimeMillis() + adddaysM);
[该贴被banq于 12:23修改过][该贴被admin于 08:14修改过][该贴被admin于 08:35修改过]
通过客户端http缓存 服务器端这些技术综合在一起,可以大大增强每台服务器抗高负载能力,把带宽留给更需要实时更新的模型或页面。这种方式比静态化页面的好处是:精确性,静态页面.html比如Apache中mod_expire设置,如设置expire为十分钟,如果过了十分钟,其实页面内容还是没有变,也要加载静态页面到客户端,而结合Etag的动态页面,不但起到静态页面一样的效果(其实经过Apache处理的静态页面html也是动态页面),而且可以做到精确制导,就象多国部队轰炸利比亚一样,精确打击。这是灵活性的魅力。所以,不要再迷信页面静态化了相关帖子:[该贴被banq于 13:44修改过]
banq 请问一下,你所说的在浏览器中直接访问是没问题的,可是如果是用ajax访问呢。ajax要不就直接读,和服务器根本没交互,要不就在url后面加个时间戳每次都是第一次访问。请问ajax里面怎么解决你所说的问题呢
日 21:21 "@"的内容ajax要不就直接读,和服务器根本没交互 ... 方式AJAX调用的URL都不要啊,也就是在服务器端不用http缓存,比如可以从URL扩展名上区分:.shtml/.do是动态不需要,而.html或无后缀名的都是有的。具体可参考jivejdon实现方法。jivejdon中间隔检查私信checkmsg.shtml是不设定,与一般动态页面一致。
举个例子:比如一个页面需要用ajax访问一个服务器上的xml文件,这个xml文件有可能会发生变化。当客户端第一次访问完成后,这个xml会被浏览器到客户端。但当第二次访问时,如果ajax设置读取,ajax就直接读客户端,这样如果xml发生变化就发现不了。如果ajax不设置读取,那就会在每个url访问后面加上时间戳,或者设置xmlHTTP.setRequestHeader("If-Modified-Since","0"),不过这样还能得到正确的结果吗。在jquery里面有ifModifiedBoolean(默认: false) 仅在服务器数据改变时获取新数据。使用 HTTP 包 Last-Modified 头信息判断。在jQuery 1.4中,他也会检查服务器指定的'etag'来确定数据没有被修改过。不过好像并不起作用
最佳分辨率
OpenSource
Code & 2002-20浏览器缓存机制 - 简书
下载简书移动应用
写了8760字,被47人关注,获得了70个喜欢
浏览器缓存机制
浏览器通过HTTP头部的字段来控制文件的缓存:要不要缓存以及缓存的过期时间。
Cache-Control/Expires
Cache-Control和Expires控制文件的缓存,在缓存文件的有效时间内,浏览器直接使用本地文件,不与服务器交互。
Cache-Control的值是一个单位为秒的数字,表示缓存文件的有效时间有多少秒。Expire的值是一个绝对时间点,表示缓存文件在某个时间点之前有效。
在Cache-Control和Expires同时存在的情况下,Cache-Control的优先级高于Expires。
下面举例说明:
Cache-Control: max-age=600
缓存文件的有效时长为600秒。在接下来600s内,如果有请求这个资源的,浏览器不会发出请求,而是直接使用本地缓存的文件。
Cache-Control: private
告诉浏览器不要缓存这个文件。
Expires: Mon, 24 Nov :46 GMT
缓存文件在 02:32:46 GMT之前有效。
Expire: -1
告诉浏览器不要缓存这个文件。
Last-Modified/Etag
Last-Modified的值是一个绝对时间点,表示文件最近一次修改的时间。Etag的值是一个文件的hash。
与上面的Cache-Control和Expire不同,如果只使用Last-Modified/Etag对文件的缓存进行控制。那每次访问文件的时候,浏览器会向服务器发起304请求,如果文件没有被修改,则使用本地文件,否则从服务器获取文件。
当Last-Modify或者Etag两者有一个和服务器上的文件相同时,则浏览器认为文件没有更新,直接使用本地缓存文件。
Last-Modified: Thu, 21 Apr :22 GMT
缓存文件的上次更新的时间是 03:17:22 GMT。
ETag: "27b7-5256d6aeaf7c0"
缓存文件的哈希值是27b7-5256d6aeaf7c0。
强制使Cache-Control/Expires失效:Cache-Control: max-age=0此时,如果文件还使用了Last-Modified/Etag进行缓存控制,则向服务器发起304请求。
强制使上面两种浏览器缓存失效:
Cache-Control:no-cachePragma:no-cache
利用浏览器缓存
理想的缓存机制应该是这样的:
缓存文件没更新,尽可能使用缓存,不用和服务器交互;
当用户刷新时,尽可能减少浏览器和服务器之间的数据传输;
缓存文件有更新时,第一时间能使用到新的文件;
缓存的文件要保持完整性,不使用被修改过的缓存文件;
缓存的容量大小要能设置或控制,缓存文件不能因为存储空间限制或过期被清除。
第4,5属于浏览器的内部机制,我们无法控制。
对于1,使用Cache-Control可以实现(Cache-Control的优先级高于Expires)。对于2,使用Last-Modified或者Etag可以实现(两者可以一起使用)。对于3,我们采用每次发布,在要缓存的资源文件名中加上版本号或文件MD5值字串的方法来实现(修改缓存文件的文件名)。
当然,这里要注意一点就是“入口”文件(html文件)是被设置为不缓存的,如Google,百度的html页面:
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
被以下专题收入,发现更多相似内容:
如果你是程序员,或者有一颗喜欢写程序的心,喜欢分享技术干货、项目经验、程序员日常囧事等等,欢迎投稿《程序员》专题。
专题主编:小...
· 195432人关注
玩转简书的第一步,从这个专题开始。
想上首页热门榜么?好内容想被更多人看到么?来投稿吧!如果被拒也不要灰心哦~入选文章会进一个队...
· 136186人关注
Android,Java
· 2157人关注
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:发帖人是女婴父亲,刚以难民身份进入德国。
经过铁路菜市的火车速度很慢,很远就要鸣笛示意。
声明:本文由入驻搜狐公众平台的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。
  计算机科学中最难的两件事是缓存失效和命名。
  -- Phil Karlton
  今天我们来简要了解一下浏览器的缓存问题。
  浏览器缓存是指当浏览器请求一个资源的时候,会在本地保存一份副本,当下一个请求来到的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是向源服务器再次发送请求。
  一、浏览器缓存的作用
  1. 减少网络带宽消耗:无论对于网站运营者或者用户,带宽都代表着金钱,过多的带宽消耗,只会便宜了网络运营商。当Web缓存副本被使用时,只会产生极小的网络流量,可以有效的降低运营成本。
  2. 降低服务器压力:给网络资源设定有效期之后,用户可以重复使用本地的缓存,减少对源服务器的请求,间接降低服务器的压力。同时,搜索引擎的爬虫机器人也能根据过期机制降低爬取的频率,也能有效降低服务器的压力。
  3. 减少网络延迟,加快页面打开速度:带宽对于个人网站运营者来说是十分重要,而对于大型的互联网公司来说,可能有时因为钱多而真的不在乎。那Web缓存还有作用吗?答案是肯定的,对于最终用户,缓存的使用能够明显加快页面打开速度,达到更好的体验。
  二、浏览器端的缓存规则
  真正的浏览器工作的时候并不是将完整的内容保存在本地,各种浏览器都有不同的方式,譬如firefox是一种类似innodb的方式存储的key value 的模式,在地址栏中输入 about:cache 可以看见缓存的文件,chrome会把缓存的文件保存在一个叫User Data的文件夹下。
  浏览器缓存有一套自己的规则,可以用来决定何时使用缓存,何时从服务器上获取资源,这些规则是在HTTP协议头和HTML页面的Meta标签中定义的。
  1. 响应头明确说明,我不想被缓存,则不会被缓存;
  2. 如果请求信息是需要认证或者安全加密的(如: HTTPS),相应内容也不会被缓存;
  3. 缓存如果有以下表现,则认为是fresh新鲜的(无需检查源服务器,直接发送给客户端),则内容缓存直取,绕过源服务器。
  ★ 含有完整的过期时间和寿命控制头信息,并且内容仍在保鲜期内。
  ★ 缓存最近已展现,并且在不久前修改。
  4. 若内容陈旧,则会要求源服务器做验证 validate ,或者告诉缓存其拷贝副本是否是OK的。
  5. 特定情况下――例如,断网了,之前有过的响应缓存直取而不检查源服务器。 总而言之,新鲜度 freshness和校验validation是确定缓存内容是否可用的两个维度。如果要展示的足够新,直接使用缓存;如果检测发现展示内容并未变化,则会直接使用缓存。下面两张图很清晰的描述了浏览器发起请求时决定是否使用缓存的机制:
  三、浏览器缓存的控制
  1. 使用 Meta 标签控制页面缓存
  前端攻城狮可以在HTML页面的节点中加入标签,代码如下:
  &meta http-equiv=&Pragma& content=&no-cache&&
  上述代码的作用是告诉浏览器当前页面不被缓存,每次访问都需要去服务器拉取。使用上很简单,但只有部分浏览器可以支持,而且所有缓存代理服务器都不支持,因为代理不解析HTML内容本身。所以并不推荐使用这种方式控制页面缓存。
  2.使用 HTTP 协议头控制页面缓存
  在HTTP请求和响应的消息报头中,常见的与缓存有关的消息报头有以下这些:
  Cache-Control 与 Expires
  Cache-Control 与 Expires 的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。只不过 Cache-Control 的选择更多,设置更细致,如果同时设置的话,其优先级高于 Expires。
  Last-Modified/ETag 与 Cache-Control/Expires
  配置 Last-Modified/ETag 的情况下,浏览器再次访问统一 URI 的资源,还是会发送请求到服务器询问文件是否已经修改,如果没有,服务器会只发送一个304回给浏览器,告诉浏览器直接从自己本地的缓存取数据;如果修改过那就整个数据重新发给浏览器。
  Cache-Control/Expires 则不同,如果检测到本地的缓存还是有效的时间范围内,浏览器直接使用本地副本,不会发送任何请求。两者一起使用时,Cache-Control/Expires 的优先级要高于 Last-Modified/ETag。即当本地副本根据 Cache-Control/Expires 发现还在有效期内时,则不会再次发送请求去服务器询问修改时间(Last-Modified)或实体标识(Etag)了。
  一般情况下,使用 Cache-Control/Expires 会配合 Last-Modified/ETag 一起使用,因为即使服务器设置缓存时间, 当用户点击“刷新”按钮时,浏览器会忽略缓存继续向服务器发送请求,这时 Last-Modified/ETag 将能够很好利用304,从而减少响应开销。
  Last-Modified与ETag
  你可能会觉得使用 Last-Modified 已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要 Etag(实体标识)呢?HTTP1.1 中 Etag 的出现主要是为了解决几个 Last-Modified 比较难解决的问题:
  ★ Last-Modified 标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的新鲜度。
  ★ 如果某些文件会被定期生成,当有时内容并没有任何变化,但 Last-Modified 却改变了,导致文件没法使用缓存。
  ★ 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形。
  Etag 是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified 与ETag 是可以一起使用的,服务器会优先验证 ETag,一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回304。
  四、浏览器缓存机制在实际开发中的应用
  服务器端可以设置缓存规则,但在服务器不能掌控的地方也许会出现一些意外。
  1. 缓存会被挤出。
  所谓缓存被挤出,因为浏览器的缓存空间是有限的,所有网站希望缓存的文件都塞在里面,形成一个先进先出的队列。所以你即使设置了20年的缓存时间,也基本上是不可能保证有那么久的生命期。而且用户也有可能主动清除浏览器缓存,某些系统清理软件也可能清理浏览器缓存。
  2. 文件有可能在运营商服务器上被劫持。
  第二个问题是用户的宽带运营商为了提高速度,可能会在自己某节点服务器上缓存你的文件(比如 style.css?v1),好处是当用户请求这个文件的时候,运营商无需来你的服务器上请求文件,而自己直接就给出了。 如果你的 querys string 更新了(style.css?v2),按照HTTP规范,这理应被视作一个新的文件。
  但是运营商仍然可能会拿自己的缓存,而不是遵循规范。有点可恶对不对?这就是我们在用户量极大的情况下侦查到的情况,所以,为了保证更新的文件确定能下发到所有的用户,我们最好是在资源文件改变时,使用前端构建工具修改文件名,而不是仅修改 query string。
  以下是业界公认的最佳规则:
  对于动态生成的html页面使用HTTP头:Cache-Control: no-cache
  对于静态html页面使用HTTP头:Last-Modified
  其他所有的文件类型都设置Expires头,并且在文件内容有所修改的时候修改文件名
  作者简介:李凡,英文名Levy,校导Web前端工程师,热衷钻研前端技术,对单页应用开发和前端工程化有着浓厚的兴趣。
欢迎举报抄袭、转载、暴力色情及含有欺诈和虚假信息的不良文章。
请先登录再操作
请先登录再操作
微信扫一扫分享至朋友圈
搜狐公众平台官方账号
生活时尚&搭配博主 /生活时尚自媒体 /时尚类书籍作者
搜狐网教育频道官方账号
全球最大华文占星网站-专业研究星座命理及测算服务机构
优质的校园活动推广和孵化平台,专注高校人才孵化,以青春的态...
主演:黄晓明/陈乔恩/乔任梁/谢君豪/吕佳容/戚迹
主演:陈晓/陈妍希/张馨予/杨明娜/毛晓彤/孙耀琦
主演:陈键锋/李依晓/张迪/郑亦桐/张明明/何彦霓
主演:尚格?云顿/乔?弗拉尼甘/Bianca Bree
主演:艾斯?库珀/ 查宁?塔图姆/ 乔纳?希尔
baby14岁写真曝光
李冰冰向成龙撒娇争宠
李湘遭闺蜜曝光旧爱
美女模特教老板走秀
曝搬砖男神奇葩择偶观
柳岩被迫成赚钱工具
大屁小P虐心恋
匆匆那年大结局
乔杉遭粉丝骚扰
男闺蜜的尴尬初夜
客服热线:86-10-
客服邮箱:}

我要回帖

更多关于 java lastmodified 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信