正文
总的来说,缓存方案分为强制缓存
和协商缓存
两类缓存机制可以同时存在,强制缓存的优先级高于协商缓存;当执行强制缓存时,如若缓存命中,则直接使用缓存数据,不在进行协商缓存。
强制缓存
强制缓存
,服务器响应的header中会用两个字段来表明:Expires
和Cache-Control
Expires
Exprires
的值为服务端返回数据的到期时间。如Expires:Thu, 02 Apr 2009 05:14:08 GMT
当再次请求服务器资源时的请求时间小于第一次请求服务器资源返回的此时间,则直接使用缓存数据。但是服务端时间和客户端时间可能有误差,会导致缓存命中的误差,另一方面,Expires是HTTP1.0的产物,故现在大多数使用Cache-Control替代。
Cache-Control
Cache-Control
有很多属性,不同的属性代表的意义也不同。
1.private
:客户端可以缓存
2.public
:客户端和代理服务器都可以缓存
3.max-age=t
:缓存内容将在t秒后失效
4.no-cache
:需要使用协商缓存来验证缓存数据
5.no-store
:所有内容都不会缓存。
协商缓存
协商缓存
需要进行对比判断是否可以使用缓存。浏览器第一次请求数据时,服务器会将缓存标识
与数据
一起响应给客户端,客户端将它们备份至缓存
中。
再次请求时,客户端会将缓存中的标识发送给服务器,服务器根据此标识判断。若未失效,返回304状态码,浏览器拿到此状态码就可以直接使用缓存数据了。
对于协商缓存来说,缓存标识我们需要着重理解一下,下面我们将着重介绍它的两种缓存方案。
Last-Modified
Last-Modified:在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时有一个Last-Modified
的属性标记(HttpReponse Header),用来此文件在服务期端最后被修改的时间,格式类似这样:
Last-Modified:Tue, 24 Feb 2009 08:01:04 GMT
if-Modified-Since:浏览器再次请求服务器的时候,请求头会包含此字段,后面跟着在缓存中获得的最后修改时间。服务端收到此请求头发现有if-Modified-Since,则与被请求资源的最后修改时间进行对比,如果一致则返回304和响应报文头,浏览器只需要从缓存中获取信息即可。
从某个时间节点算起,是否文件被修改了
1.如果真的被修改:那么开始传输响应一个整体,服务器返回:200 OK
2.如果没有被修改:那么只需传输响应header,服务器返回:304 Not Modified
if-Unmodified-Since:从某个时间点算起, 文件是否没有被修改
1.如果没有被修改:则开始`继续’传送文件: 服务器返回: 200 OK
2.如果文件被修改:则不传输,服务器返回: 412 Precondition failed (预处理错误)
这两个的区别是一个是修改了才下载一个是没修改才下载。 Last-Modified 说好却也不是特别好,因为如果在服务器上,一个资源被修改了,但其实际内容根本没发生改变(比如资源修改后又还原过来),会因为Last-Modified时间匹配不上而返回了整个实体给客户端(即使客户端缓存里有个一模一样的资源)。为了解决这个问题,HTTP1.1推出了Etag。
Etag
Etag:服务器响应请求时,通过此字段告诉浏览器当前资源在服务器生成的唯一标识(生成规则由服务器决定)
类似服务器端返回的格式:Etag:"5d8c72asedda8d6a:6239"
If-None-Match:再次请求服务器时,浏览器的请求报文头部会包含此字段,后面的值为在缓存中获取的标识。
比如:If-None-Match:"5d8c72asedda8d6a:6239"
服务器接收到次报文后发现If-None-Match则与被请求资源的唯一标识进行对比。
1.不同,说明资源被改动过,则响应整个资源内容,返回状态码200。
2.相同,说明资源无心修改,则响应header,浏览器直接从缓存中获取数据信息。返回状态码304.
但是实际应用中由于Etag的计算是使用算法来得出的,而算法会占用服务端计算的资源,所有服务端的资源都是宝贵的,所以就很少使用Etag了。
不同刷新的请求执行过程
- 浏览器地访问URL,浏览器发现缓存中有这个文件了,不用继续请求了,直接去缓存拿。(最快)
- 按下F5,告诉浏览器,别偷懒,好歹去服务器看看这个文件是否有过期了。于是浏览器就胆胆襟襟的发送一个请求带上If-Modify-since。
- 按下Ctrl+F5,告诉浏览器,你先把你缓存中的这个文件给我删了,然后再去服务器请求个完整的资源文件下来。于是客户端就完成了强行更新的操作.
本文首次发布于 孙忠良 Blog, 作者 [@sunzhongliang] , 转载请保留原文链接.