一、Last-Modified和If-Modified-Since
简单地说,Last-Modified和If-Modified-Since都是用于记录页面最后修改时间的HTTP头信息,只是Last-Modified是由服务器向客户端发送的HTTP响应头;而If-Modified-Since则是由客户端往服务器发送的请求头;
当再次请求本地存在的缓存页面时,客户端会通过If-Modified-Since头把浏览器缓存在页面的最后一次被服务器修改的时间一起发到服务器去,
服务器会把这个时间与服务器上实际文件的最后修改时间进行比较,通过这个时间戳判断客户端的页面是否是最新的:
如果不是最新的,就返回HTTP状态码200和新文件内容,客户端收到之后,会丢弃旧文件,把新文件缓存起来,并显示到浏览器中;
如果是最新的,则返回304告诉客户端其本地缓存的页面是最新的,就直接把本地缓存文件显示到浏览器中,这样在网络上传输的数据量就会大大减少,同时也减轻了服务器的负担。
1、什么是“Last-Modified”?
在浏览器第一次请求某一个URL时,服务器端的返回状态是200,内容是你请求的资源,同时有一个Last-Modified的属性标记此文件在服务器端最后被修改的时间,格式类似这样:Last-Modified:Fri, 12 May 2010 18:53:33 GMT
客户端第二次请求此URL时,浏览器会向服务器传送If-Modified-Since报头,询问该时间之后文件是否有被修改过:If-Modified-Since: Fri, 12 May 2010 18:53:33 GMT
如果服务器的资源没有变化,则自动返回HTTP 304状态码,内容为空,这样就节省了传输数据量。
如果服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类似,从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
二、ETag和 If-None-Match
ETag和 If-None-Match是一种常用的判断资源是否改变的方法。类似于Last-Modified和If-Modified-Since。
但是有所不同的是Last-Modified和If-Modified-Since只判断资源的最后修改时间,而ETag和 If-None-Match可以是资源的任何属性,比如资源的MD5等。
ETag和 If-None-Match的工作原理是在HTTP Response Headers中添加ETags信息。当客户端再次请求该资源时,将在HTTP Request Headers中加入If-None-Match信息(也就是ETags的值)。
如果服务器验证资源的ETags没有改变(该资源的内容没有改变),将返回一个304状态;否则,服务器将返回200状态,并返回该资源和新的ETags。
1)什么是“ETag”?
服务器为每个资源分配对应的ETag值,根据资源的内容得到其值。当资源内容发生改变时,其值也会改变。以下是服务器端返回的格式:
ETag:"50b1c1d4f775c61:df3"
客户端的查询更新格式是这样的:
If-None-Match:W/"50b1c1d4f775c61:df3"
如果ETag没有改变,则返回状态304,这也和Last-Modified一样。
扩展1:Last-Modified和ETags如何帮助提高性能?
聪明的开发者会把Last-Modified和ETags请求的HTTP报头一起使用,这样可利用客户端的缓存。因为服务器首先产生Last-Modified/Etag标记,服务器可在稍后使用它来判断页面是否已经被修改。本质上,客户端通过将该记号传回服务器要求服务器验证其(客户端)缓存。
扩展2:既然有了Last-Modified,为什么还要用ETag字段呢?
1)某些文件修改非常频繁,比如在秒以下的时间内进行修改,If-Modified-Since能检查到的粒度是秒级的,这种修改无法体现。
2)一些文件也许会周期性的更改,但是它的内容并不改变(仅仅改变修改的时间)【此时服务端资源内容并未改变,所以ETag值并不改变】,这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
3)某些服务器不能精确的得到文件的最后修改时间。
3、Expires/Cache-Control(优先使用)
用来控制缓存的失效日期,控制浏览器是直接从浏览器缓存取数据还是重新发请求到服务器取数据。
Expires是web服务器响应消息头字段,在响应HTTP请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。
Expires的一个缺点是,返回的到期时间是服务器端的时间。这样就存在一个问题,如果客户端的时间与服务器的时间相差很大(比如时间不同步,或者跨时区),那么误差就很大。
所以在HTTP1.1版开始,使用Cache-Control: max-age=(秒)替代。
当服务器发出响应的时候,可以通过两种方式来告诉客户端缓存请求:【通知客户端是否可以缓存该服务端返回的资源】
第一种是Expires,比如:Expires: Sun, 16 Oct 2016 05:43:02 GMT
不过Expires有缺点,比如说,服务端和客户端的时间设置可能不同,这就会使缓存的失效可能并不能精确地按服务器的预期进行。
第二种是Cache-Control,比如:Cache-Control: max-age=315360000
这里声明的是一个相对的秒数,表示从现在起,315360000秒内缓存都是有效的,这样就避免了服务端和客户端时间不一致的问题。
但是Cache-Control是HTTP1.1才有的,不适用于HTTP1.0,而Expires既适用于HTTP1.0,也适用于HTTP1.1,所以说在大多数情况下,同时发送这两个头回是一个更好的选择,当用户端两种头都能解析的时候,会优先使用Cache-Control。
过程如下:
(1)客户端请求一个页面(A)。
(2)服务器返回页面A,并再给A加上一个Last-Modified和ETag。
(3)客户端展现该页面,并将页面连同Last-Modified和ETag的值一起缓存。
(4)客户再次请求页面A,并将上次请求时服务器返回的Last-Modified和ETag的值一起传递给服务器。
(5)服务器检查该Last-Modified或ETag,并判断出该页面资源自上次客户端请求之后还未被修改,直接返回响应304和一个空的响应体。
实例
1.首先在服务器创建一个简单的HTML文件,用浏览器访问一下,成功表示HTML页面。Fiddler就会产生下面的捕获信息。
需要留意的是:
(1)因为是第一次访问该页面,客户端发请求时,请求头中没有If-Modified-Since标签。
(2)服务器返回的HTTP状态码是200,并发送页面的全部内容。
(3)服务器返回的HTTP头标签中有Last-Modified,告诉客户端页面的最后修改时间。
2.在浏览器中刷新一下页面,Fiddler就会产生下面的捕获信息。
需要注意的是:
(1)客户端发HTTP请求时,使用If-Modified-Since标签,把上次服务器告诉它的文件最后修改时间返回到服务器端了。
(2)因为文件没有改动过,所以服务器返回的HTTP状态码是304,没有发送页面的内容。
3.用文本编辑器稍微改动一下页面文件,保存。再用浏览器访问一下,Fiddler就会产生下面的捕获信息。
需要注意的是:
(1)客户端发HTTP请求时,使用If-Modified-Since标签,把上次服务器告诉它的文件最后修改时间返回到服务器端了。
(2)因为文件被改动过,两边的时间不一致,所以服务器返回的HTTP状态码是200,并发送新页面的全部内容。
(3)服务器返回的HTTP头标签中有Last-Modified,告诉客户端页面的新的最后修改时间。