web缓存的工作原理
所有的缓存都是基于一套规则来确定什么时候使用缓存的副本提供服务。这些规则有的可以通过协议定义(比如HTTP1.0和HTTP1.1),有的也可以通过缓存的管理员设置(如DBA、代理服务器管理员或者开发者等)。
浏览器端的缓存机制
简单来说,就是把副本保存在了本地,不需要每次都向服务器端请求。但是每次读取缓存就会有问题,假如服务器端的内容更新了呢?因此,服务器端会和客户端约定一个有效期,在有效期内的可以直接读缓存。
但是,假如有效期过了,但是服务器端的内容依然没有改变呢,其实这个时候还是可以读缓存的,只是需要通过判断得知服务器端内容是否改变。
大抵就是这两个需要考虑的问题:
- 如何判断有效期(新鲜度,过期机制)
- 如果超出有效期,服务器端内容是否改变 (校验值,验证机制)
浏览器缓存的控制
- 使用HTML标签
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
上述代码的作用是告诉浏览器当前页面不被缓存,每次访问都需要去服务器拉取。使用上很简单,但只有部分浏览器可以支持,而且所有缓存代理服务器都不支持,因为代理不解析HTML内容本身。
- 使用HTTP协议头
Cache-control VS Expires
作用一致,都指有效期,不过cache-control选择更多更细致,优先级也更高。
Last-Modified/ETag
如果缓存内容超出有效期,则需要去服务器端验证是否是最新的,此时则通过Last-Modified/ETag值来验证。
Last-Modified/If-Modified-Since
这是验证服务器端文件是否更新的第一种方式。
如图所示,在第一次请求时,响应头会将Last-Modified信息返回。
在按下ctrl+r强制刷新时,请求会跳过max-age和Expires向服务器端发送请求,并在Request Headers中加入If-Modified-Since值,该值就是上一次请求中的Last-Modified值。
ETag/If-None-Match
这是验证服务器端是否更新的第二种方式。
实际上ETag并不是文件的版本号,而是一串可以代表该文件唯一的字符串(Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。)
当客户端发现和服务器约定的直接读取缓存的时间过了,就在请求中发送If-None-Match选项,值即为上次请求后响应头的ETag值,该值在服务端和服务端代表该文件唯一的字符串对比(如果服务端该文件改变了,该值就会变),如果相同,则相应HTTP304,客户端直接读取缓存,如果不相同,HTTP200,下载正确的数据,更新ETag值。
如果Request Headers中既有If-None-Match又有If-Modified-Since,则忽略If-Modified-Since。因为ETag解决了Last-Modified的几个问题:
- Last-Modified只能精确到秒级别
- 有时候文件的时间虽然变了,但是内容却没有改变