HTTP协议缓存原理解析

导语

  在web项目开发中,我们可能都曾碰到过这样一个棘手的问题:

  线上项目需要更新一个有问题的资源(可能是图片、js、css、json数据等),这个资源已经发布了很长一段时间,为什么页面在浏览器里打开还是没有看到更新?

  有些web开发经验的同学应该马上会想到,可能是资源发布出了岔子导致没有实际发布成功,更大的可能是老的资源被缓存了。说到web缓存,首先我们要弄清它是什么。Web缓存可以理解为Web资源在Web服务器和客户端(浏览器)的副本,其作用体现在减少网络带宽消耗、降低服务器压力和减少网络延迟,加快页面打开速度等方面(笔者在香港求学期间看到港台地区将cache译为“快取”,除了读音相近,大概就是贴近这层含义)。他们通常还会告诉你:Ctrl+F5强刷一下,但是本文下面的内容将会说明为什么强制刷新在去除缓存上不总是能奏效的,更何况对于线上项目而言,总不能让所有已经访问过的用户撸起袖子岔开两个手指都强制刷新一下吧?

1、Http协议缓存

  回到开头的那个问题,更新了一张图片,发布之后反复重新进页面总是看不到更新,这是为什么呢?

  这里我们假设已经排除了资源没有发布成功过的情况,那么第一步,我们可能会认为是http协议缓存(也称为浏览器缓存或者网页缓存)。

  http协议缓存机制是指通过HTTP协议头里的 Cache-Control(或 Expires)和 Last-Modified(或 Etag)等字段来控制文件缓存的机制。

  • Cache-Control用于控制文件在本地缓存的有效时长。最常见的,比如服务器回包:Cache-Control:max-age=600表示文件在本地应该缓存,且有效时长是600秒(从发出请求算起)。在接下来600秒内,如果有请求这个资源,浏览器不会发出HTTP请求,而是直接使用本地缓存的文件。

  • Last-Modified是标识文件在服务器上的最新更新时间。下次请求时,如果文件缓存过期,浏览器通过If-Modified-Since字段带上这个时间,发送给服务器,由服务器比较时间戳来判断文件是否有修改。如果没有修改,服务器返回304告诉浏览器继续使用缓存;如果有修改,则返回200,同时返回最新的文件。

  Cache-Control通常与Last-Modified一起使用。一个用于控制缓存有效时间,一个在缓存失效后,向服务查询是否有更新。

  Cache-Control还有一个同功能的字段:Expires。Expires的值是一个绝对的时间点,如:Expires: Thu, 10 Nov 2015 08:45:11 GMT,表示在这个时间点之前,缓存都是有效的。

  Expires是HTTP1.0标准中的字段,Cache-Control是HTTP1.1标准中新加的字段,功能一样,都是控制缓存的有效时间,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。只不过Cache-Control的选择更多,设置更细致。当这两个字段同时出现时,Cache-Control 是高优化级的。

  Last-Modified/If-Modified-Since要配合Cache-Control使用。

  • Last-Modified:标示这个响应资源的最后修改时间,web服务器在响应请求时,通过这个字段告诉浏览器资源的最后修改时间。

  • If-Modified-Since:当缓存的资源过期时(通过Cache-Control标识的max-age判断),浏览器发现资源具有Last-Modified声明,则再次向web服务器请求时带上头If-Modified-Since,表示请求时间。web服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。

  Etag在HTTP1.1中有介绍,主要的作用就是在(css file, image, javascript file)文件后面添加一个唯一的参数(相当于查询参数字符串),Etag由服务器端生成,并且随着文件的改变而改变,这样浏览器端就会只重新请求获取Etag发生变化的文件,减少浏览器端数据的流量,加快浏览器的反应速度,重要的是减轻服务器端的压力。

  Etag也和Last-Modified一样,对文件进行标识的字段。不同的是,Etag的取值是一个对文件进行标识的特征字串。在向服务器查询文件是否有更新时,浏览器通过If-None-Match字段把特征字串发送给服务器,由服务器和文件的最新特征字串进行匹配,来判断文件是否有更新。没有更新回包304,有更新回包200。Etag和Last-Modified可根据需求使用一个或两个同时使用。两个同时使用时,只要满足基中一个条件,就认为文件没有更新。

  • Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。

  • If-None-Match:当缓存的资源过期时(通过Cache-Control标识的max-age值来判断),浏览器发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match (Etag的值),web服务器收到请求后发现有头If-None-Match则与被请求资源的相应校验串进行比对,决定返回200或304

  Etag主要为了解决Last-Modified无法解决的一些问题,

  你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag(实体标识)呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:

  (1).Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间。ETag能比Last_Modified更加精确地知道文件是否被修改过,如果文件在秒以下的时间内多次修改,比如1秒内修改了10次,If-Modified-Since只能检查秒级的修改,所以对这种修改无法判断。原因是UNIX记录MTIME只能精确到秒,所以我们选择生成Etag,因为Etag可以综合Inode、MTime和Size,可以避免这个问题。

  (2).如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存。

  (3).有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形。

  Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304

2、用户行为与缓存

  浏览器缓存行为还与用户的行为有关!!!具体关系如下:

  有两种情况比较特殊:

  手动刷新页面(F5),浏览器会直接认为缓存已经过期(可能缓存还没有过期),在请求中加上字段:Cache-Control:max-age=0,发包向服务器查询是否有文件是否有更新。

  强制刷新页面(Ctrl+F5),浏览器会直接忽略本地的缓存(有缓存也会认为本地没有缓存),在请求中加上字段:Cache-Control:no-cache(或 Pragma:no-cache),发包向服务重新拉取文件。

  当然,各个浏览器对于刷新和强制刷新的实现方式也有一些区别。

  那么,如果线上更新了web资源,如何能让尽快更新呢?(要知道像图片这样比较少更新的资源一般缓存时间都设置得比较长,比如game.gtimg.cn域名下是一天,有问题的图片在用户侧缓存这么长时间是不可接受的)

  方法一 修改请求header头,比如php添加:

header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");

  方法二 修改html的head块

<META HTTP-EQUIV="pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<META HTTP-EQUIV="expires" CONTENT="Wed, 26 Feb 1997 08:21:57 GMT">
<META HTTP-EQUIV="expires" CONTENT="0">

  方法三:添加随机参数

  对于js可以直接使用时间戳:

<script language="javascript" src="UILib/Common/Common.js?time=new Date()">

3、总结

  浏览器第一次请求:

  

  浏览器再次请求:

  注:上图中的“Etag?”表示“has Etage?”,“Last-Modified?”表示"has Last-Modified?",向服务器请求带If-None-Match时,服务器会检查收到的头If-None-Match与被请求资源的相应校验串是否匹配,决定返回200或304。


参考资料:
http://geek.csdn.net/news/detail/203704
http://www.t086.com/article/4245
http://blog.csdn.net/moshenglv/article/details/52020563

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值