http协议缓存
缓存的目的:
减少相应延迟、减少网络带宽消耗
实际项目:
使用反向代理服务器(NGINX或apache)进行缓存
关键字:
cache-control、expire、if-none-match、if-modified-since、etag、last-modified
静态资源请求处理过程:
1、本地缓存阶段:先在本地查找该资源,如果有发现资源,并且未过期,直接使用,不发送http请求
2、协商缓存阶段:如果本地发现该资源,但是不确认是否过期,则发送一个http请求到服务器,然后服务器判断该请求,如果发现未改动,则返回304,让浏览器使用本地资源
3、缓存失败阶段:当服务器发现资源改动了,或者这是一个新请求(本地找不到该资源),服务器则返回该资源数据,并返回状态200,如果服务器未找到该资源,则返回404
问题:
1、本地缓存阶段,如何判断资源是否过期?
2、协商缓存阶段,如何判断本地资源是否和服务器的资源是否一样?
关键字解析:
expire:
如果apache开启了expire模块, 当浏览器发送该资源请求的时候, apache返回资源的同时,会返回一个名为expire的http头,expire头的内容是一个时间值, 这一个值就是资源在本地的过期时间, 这个值会存在本地.
也就是说,在本地缓存阶段,在本地找到了一个对应的资源值,而且当前时间还没超过资源的过期时间, 那么就直接使用这一个资源,不会发送http请求.
cache-control:
负责控制页面的缓存机制,如果该头部指示缓存,缓存的内容也会存在本地,操作流程和expire类似,但是有不同的地方,cache-control有更多选项,也有更多处理方式
a、Public
指示该响应内容可以被任何缓存区缓存
b、Private
指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
c、no-cache
指示请求或响应消息不能被缓存
d、no-store
用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存
e、max-age
指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
f、no-transform
不允许转换存储系统
g、must-revalidate
使得客户端再次浏览本页面时,必须再次发送相关http头信息到服务器进行验证,再决定是否加载客户端缓存
h、if-modified-since和last-modified
当apache接收到一个资源请求(假设是用户是第一次访问,没有任何缓存), 服务器返回资源的同时,还会发送一个last-modified的http响应头, last-modified响应头的内容值是该资源在服务器上最后修改的时间.浏览器接受到这个http头后,会把其内容值和资源同时保存起来.
当用户第二发送资源请求(假设这里expire没有生效或者已经过期), 浏览器在本地找到了一个相同的资源,但是不能确定该资源是否和服务器上的一样(有可能在两次访问期间,服务器上的资源已经被修改过),此时浏览器发送请求的时候,请求头内会附带一个if-modified-since的请求头, 这个头部的内容就是上一次last-modified返回的值, 服务器把这个头的值和请求资源的最后修改时间对比,如果两个值相同,则认为资源没有修改,将会返回304,让浏览器使用本地资源.否则服务器将返回资源,而且返回200状态
i、if-none-match和etag
其实这两个头部和if-modified-since, last-modified的工作原理是一样的, if-none-match作为请求头, etag作为响应头.既然工作原理一样, 为什么etag这对头部会出现呢?
原因在于, last-modified请求头的内容是以文件最后修改的时间作为对比的,但是unix系统里面, 文件修改的时间只保存到了秒. 如果某些应用内存在1秒内对文件做了多次修改,这样last-modified是不能完成比较功能的.所以要引入一个新的机制(原因可能不止这一个);
etag的值一般由3个数值组成,资源的inode值, 最后修改时间, 资源大小,以16进制组成一个字符串, 例如:1a-182b-10f; 但这个格式不是固定的, 只要保证该值的唯一性,但不限格式.
浏览器操作对缓存的影响
1、强制刷新-当按下ctrl+F5的时候,浏览器会绕过所有缓存(本地缓存和协商缓存),直接让服务器返回最新的资源
2、普通刷新-当按下F5的时候,浏览器会绕过本地缓存来发送请求到服务器,此时,协商缓存是有效的
3、回车或转向-当在地址栏输入回车或点击转向按钮时,所有缓存都生效
cache-control 和expire
1、两者都是控制本地缓存的头部,两者同时存在时
2、expire会被cache-control的max-age覆盖
3、expire的值是一个确定的日期,而max-age的值是一个以秒为单位的数字访问,表示生存时间
4、expire只针对静态资源,cache-control针对所有页面,但默认为所有动态页面不缓存(比如index.php页面)
Pragema和cache-control
pragma是http/1.0实现的头部, pragma的值会出现在页面meta标签的http-equiv属性中,以此来控制页面缓存
cache-control是http/1.1实现的头部,在http/1.0下不兼容.
if-modified-since和if-none-match的优先级
服务器会优先验证if-modified-since请求头,再验证if-none-match,但是必须要两者头通过验证的时候才返回304,其中一个验证失败,都将返回新资源和200状态
如何让资源尽快更新?
方法一、修改请求header头,比如php的header:
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">
方法三:添加随机参数:
<img src="./data/avatar_mingpian_bak.jpg?rand=h9xqeI" width="156" height="98">
对于js,可以直接用时间戳
<script language="javascript" src="UILib/Common/Common.js?time=new Date()">
总结:
浏览器第一次请求:
浏览器再次请求: