请求头中包含了If-Modified-Since项,而它的值和上次请求响应头中的Last-Modified一致,我们发现这个日期是在遥远的2013年,也就是说这个jquery文件自从2013年的那个日期后就没有再被修改过了。将If-Modified-Since的日期和服务端该文件的最后修改日期对比,如果相同,则响应HTTP304,从缓存读数据;如果不相同文件更新了,HTTP200,返回数据,同时通过响应头更新last-Modified的值(以备下次对比)。
ETag/If-None-Match而ETag/If-None-Match则是上文大话中说的第二种check服务端文件是否更新的方式,也要配合Cache-Control使用。实际上ETag并不是文件的版本号,而是一串可以代表该文件唯一的字符串(Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。),当客户端发现和服务器约定的直接读取缓存的时间过了,就在请求中发送If-None-Match选项,值即为上次请求后响应头的ETag值,该值在服务端和服务端代表该文件唯一的字符串对比(如果服务端该文件改变了,该值就会变),如果相同,则相应HTTP304,客户端直接读取缓存,如果不相同,HTTP200,下载正确的数据,更新ETag值。
看如上截图,与服务器约定的直接读取本地缓存的时间过了,就会向服务器发送新的请求,请求头中带If-None-Match项,该字符串值会在服务端进行匹配,很显然,并没有什么变化(看响应头的ETag值),于是响应HTTP304,直接读取缓存。或许你会发送该请求也有If-Modified-Since项,如果两者同时存在,If-None-Match优先,忽略If-Modified-Since。或许你会问为什么它优先?两者功能相似甚至相同,为什么要同时存在?HTTP1.1中ETag的出现主要是为了解决几个Last-Modified比较难解决的问题:
Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
如果某些文件会被定期生成,但有时内容并没有任何变化(仅仅改变了时间),但Last-Modified却改变了,导致文件没法使用缓存
有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形
不能缓存的请求当然并不是所有请求都能被缓存。
无法被浏览器缓存的请求:
HTTP信息头中包含Cache-Control:no-cache,pragma:no-cache(HTTP1.0),或Cache-Control:max-age=0等告诉浏览器不用缓存的请求
需要根据Cookie,认证信息等决定输入内容的动态请求是不能被缓存的
经过HTTPS安全加密的请求(有人也经过测试发现,ie其实在头部加入Cache-Control:max-age信息,firefox在头部加入Cache-Control:Public之后,能够对HTTPS的资源进行缓存)
POST请求无法被缓存
HTTP响应头中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的请求无法被缓存
用户行为与缓存浏览器缓存过程还和用户行为有关,譬如上面提到的,打开我的主页simplify the life,有个jquery的请求,如果直接在地址栏按回车,响应HTTP200(from cache),因为有效期还没过直接读取的缓存;如果ctrl+r进行刷新,则会相应HTTP304(Not Modified),虽然还是读取的本地缓存,但是多了一次服务端的请求;而如果是ctrl+shift+r强刷,则会直接从服务器下载新的文件,响应HTTP200。
通过上表我们可以看到,当用户在按F5进行刷新的时候,会忽略Expires/Cache-Control的设置,会再次发送请求去服务器请求,而Last-Modified/Etag还是有效的,服务器会根据情况判断返回304还是200;而当用户使用Ctrl+F5进行强制刷新的时候,只是所有的缓存机制都将失效,重新从服务器拉去资源。
更多可以参考浏览器缓存机制
总结盗图浏览器缓存机制,两张图很清晰