这里主要讲一下Web缓存,Web缓存是可以自动保存常见文档副本的HTTP设备。当Web请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地存储设备而不是原始服务器中提取这个文档。缓存的好处有以下几点:
1. 减少冗余的数据传输,节省网络费用;
2. 缓解网络瓶颈问题,不需要更多带宽就能更快加载页面;
3. 降低了对服务器的要求,使得服务器可以更快响应;
4. 降低了距离时延。
缓存分为私有缓存和公有缓存。私有缓存是个人的缓存,包含了单个用户最常用的页面;公有缓存中包含了某个用户团体的常用页面。
私有缓存不需要很大的存储空间,浏览器中往往就有自建的私有缓存。而公有缓存是特殊的共享代理服务器,代理缓存会从本地缓存中提供文档或者代表用户与服务器进行联系。
下面介绍对一条HTTP GET报文的基本缓存处理过程:
1. 接收,缓存从网络中读取抵达的请求报文;
2. 解析,缓存对报文进行解析,提取出URL和各种首部;
3. 查询,缓存查看是否有本地副本可用,如果没有,就获取一份副本,并将其保存在本地;
4. 新鲜度检验,缓存查看已缓存副本是否足够新鲜,如果不是,则询问服务器是否有任何更新;
5. 创建响应,缓存会用新的首部和已缓存的主体来构建一条响应报文;
6. 发送,缓存通过网络将响应发回客户端;
7. 日志,缓存可选地创建日志来描述这个事务。
如图:
Cache-Control:max-age 用来说明多长时间内将这些内容视为新鲜的。在缓存文档过期之前,缓存可以以任意频率使用这些副本,而无需与服务器联系。
过期响应首部如下:
服务器再检验
一旦已缓存文档过期,缓存就必须和服务器进行核对。这里需要注意一点,就是仅仅过期并不意味着该缓存文档就和服务器上的文档不一样,所以还需要进行核对。这就叫做服务器再验证。
如何进行再验证呢?这个时候就可以利用HTTP的条件方法了,请求服务器只有在文档和缓存中不同时,才发送主体。5个条件方法中有两个适用于该场景,
最常见的缓存再验证首部是If-Modified-Since。只有自从某个日期之后资源发送了变化的时候,该请求才会指示服务器执行请求。如果自指定日期后,文档被修改了,GET就会成功执行。如果文档没有被修改,就会返回客户端一个304 Not Modified响应报文,为了提高有效性,不会返回主体。如下图:
有些情况下,仅仅使用If-Modified-Since还不够。比如有些文档可能被修改了,但是所做的修改并不重要比如是注释子类的,那么就不需要世界范围内的缓存都重新装载一次。这个时候,就可以利用If-None-Match了。对实体标签进行比较。实体标签是附加到文档上的任意标签或者引用字符串。和上面一样,如果未改变同样返回304,如下图:
下图是百度的缓存例子
可以看到响应中的etag和请求中的标签一致。
缓存控制
可以通过对Web服务器的配置来控制。也有一种简单的办法就是在网页中添加<META HTTP-EQUIV>标签来指定过期时间,如下图:
但是这样的效果并不好,因为至此该标签的浏览器使用Cache-Control规则可能会与代理缓存所用的规则不一样,导致发生混乱。所以经过正确配置服务器发送HTTP首部来交流对文档的缓存控制的唯一可靠的方法。
cookie
cookie是当前识别用户,实现持久会话最好的方式。cookie可以分为两类:会话cookie和持久cookie。会话cookie是一种零时cookie,它记录了用户访问站点时的设置和偏好,用户退出浏览器时,会话cookie就会删除。持久cookie生存时间较长,它存储在硬盘上。两者的区别就在于它们的过期时间,如果设置了Discard参数,或者没有设置Expires和Max-Age参数,这个cookie就是一个会话cookie。举个例子:
该响应头中的cookie就是持久cookie。