HTTP中的缓存控制

技术博客 / Web   2015-07-24 16:33:41  阅读量: 3520
  HTTP   优化   nginx  

Web缓存是可以自动保存常见文档副本的HTTP设备。当Web请求抵达缓存时,如果本地有"已缓存的副本",就可以从本地存储而不是原始服务器中提取这个文档,使用缓存有以下优点:

  • 减少冗余的数据传输,节省了网络费用。

  • 缓解了网络瓶颈问题,不需要更多的带宽就能更快的加载页面。

  • 降低了对原始服务器的要求,服务器可以更快的响应,避免过载的情况。

  • 降低了距离延时。

对于一个网页,如果不设置缓存,则所有资源,包括页面,css,js,图片等都要向原始服务器发出请求获取,资源的加载如图所示:

对于一个几十KB的js,css或者图片文件来说,加载往往需要花费数秒的时间,加载整个网页所需的时间往往很长。而另一方面,这些js,css和图片文件并不是需要经常更新的,在某种程度上是不需要变更的静态文件,如果每次都要从原始服务器请求相同的资源,不仅是对网络资源的浪费,也不能获得很好的浏览体验,所以,将这些静态文件缓存到本地,是一种更好的解决方法,不仅能够提升浏览体验,也能节省网络资源。

对于HTTP协议来说,Web缓存的基本原理大多很简单。对于一条HTTP GET报文的基本缓存处理过程包括7个步骤:

  1. 接收:缓存从网络中读取抵达的报文请求。

  2. 解析:缓存对报文进行解析,提取出URL和各种首部。

  3. 查询:缓存查看是否有本地副本可用,如果没有,就从原始服务器获取一份,并保存在本地。

  4. 新鲜度检测:缓存查看已缓存的副本是否足够新鲜,如果不是,就询问服务器是否有更新。

  5. 创建响应:缓存会用心的首部和已缓存的主题来构建一条响应报文。

  6. 发送:缓存通过网络将响应发回给客户端。

  7. 日志:缓存可选的创建一个日志来描述这个事物。

缓存处理的流程图如图所示:

对于缓存来说,最重要的是需要保持副本的新鲜度,使已缓存文档与服务器上的文档一致,毕竟,文档可能会随时间发生变化。为了保持副本的新鲜度,HTTP主要使用时间过期条件验证两种方式来控制。

  • 时间过期方法:

通过特殊的HTTP Cache-control首部和Expires首部,HTTP让原始服务器向每个文档附加了一个“过期时间”,这些首部说明了在多长时间内可以将内容是为新鲜的。

  1. Cache-control: max-age: max-age值定义了文档的最大使用期:从第一次生成文档到文档不再新鲜,无法使用为止,最大合法生存时间(以秒为单位)Cache-control: max-age=48200

  2. Expires: 指定了一个绝对的过期日期。如果过期日期已经过了,那么文档就不再新鲜了。

这两种方法都定义了一个文档缓存副本的有效期,在有效期内,缓存可以任意使用这些副本,而无需与服务器联系。如果副本过期,则需要通过服务器进行再验证,分两种情况:

  1. 如果再验证显示内容发生变化,缓存会获取新的文档副本,并将其存储在旧文档的位置上,然后将其发送给客户端。

  2. 如果再验证显示内容无变化,缓存只需要获取新的首部,包括一个新的过期日期,并对缓存中的首部进行更新就行。

但与此同时,也可能存在在有效期内,缓存内容发生变化的情况,这时候就需要考虑使用条件验证方法。

  • 条件验证方法:

HTTP的条件方法是一种就内容变更的方法,只有当文档与缓存中现有副本不同时,才回送对象主体。该方法同样使用两个特殊的首部来进行验证。

  1. If-Modified-Since:<date>:如果指定日期后,文档被修改,则If-Modified-Since条件为真,通常GET就会成功执行。携带新首部的新文档就会返回给缓存,新首部除了其他信息之外,还包括一个新的过期日期。如果条件为假,则会向客户端返回一个小的304 Not Modified响应报文,而不返回文档的主体,客户端也直接使用缓存的副本。

  2. If-None-Match:实体标签再验证。在时间验证方法失效的情况下,HTTP允许用户对被称为失体标签(Etag)的“版本标识符”进行比较。实体标签是附加在文档上的任意标签,它们可能包含了文档的序列号和版本号等文档唯一的指纹信息。当文档被修改时(即Etag发生变化),缓存通过比较副本和服务器文档的Etag标签,就可以用If-None-Match条件首部来GET文档的新副本。若Etag未发生变化,则返回一条304 Not Modified响应报文,不返回文档主体。

使用时间过期和条件验证方法,就可以保证本地文档缓存副本与服务器文档内容保持一致,并进行定期更新。

Nginx中相关配置

要在Nginx中使用缓存,可相应配置时间过期和条件验证的方法。在这个网站中,我们使用expires和Etag来进行配置。

  • 使用Etag:

etag on;
  • 使用Expires:

location ~* \.(jpe?g|png|gif|swf|bmp|ico)$ {
    expires 50d;
}
location ~* \.(css|js|xml|json)$ {
    expires 20d;
}

由此,便能对静态资源添加etag和expires首部,实现这些资源的缓存。

重新加载网页,可以看到使用缓存的资源的加载情况,如图所示:

可见,与前面未使用缓存的情况相比,使用缓存的资源的加载时间仅为几百毫秒,Size为B级别,仅用于返回304状态码,而不是资源的实体,由此便大大提升了网页的访问速度。

查看某个css文件的首部,如图所示:

可以看到对应的Expires,Etag,max-age都已进行设置,如此便配置好了相关资源的缓存。

在本网站中,仅仅使用了客户端来进行缓存,在其他的使用场景中,可以配置代理缓存,多级缓存等,以此来进一步提升性能。具体说明可参考《HTTP权威指南》。