小知识,大挑战!本文正在参与“ 程序员必备小知识 ”创作活动
本文同时参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金
背景:为什么需要缓存?
用缓存就会减少请求次数,大大减少带宽,也提高用户体验。
http缓存分为强缓存和协商缓存,就这两部分进行展开;强缓存优于协商缓存进行
强缓存:
强缓存情况1:
等同于第一次发送请求,没有缓存信息,直接向服务端请求
强缓存情况2:
强缓存成功,成功从浏览器缓存中拿到数据,不需要请求服务端
强缓存情况3:
如果强缓存过期则会进行协商缓存,
这种情况首先需要通过字段检查强缓存,http/1.0用的是expires字段,http/1.1用的是cache-control字段。
expires指的是过期时间点,是存在服务端返回的响应头中,用来说明在一定时间之前都不用在发送请求,直接从缓存中可以拿数据。但是这个字段方式存在一个bug,就是会有服务器的时间与客户端时间不同,那这个过期时间就回存在问题。所以在http1.1中就开始使用cache-control字段。
Cache-contro字段中可以使用max-age=time来设置一个时间。用来解释数据可以存多久。这个是与expires本质上的不同。当然cache-control字段还有很多其他属性:
public:允许客户端和代理服务器都可以进行缓存;
private:只能进行浏览器缓存,中间代理不可以尽享缓存;
no-store:不可进行缓存;
S-maxage:用来表示代理服务器缓存时间;
Must- revalidate:加上这个字段后一旦缓存过期,就必须回到源服务器验证;
No-cache:跳过当前强缓存,发送http请求,直接进入协商缓存。
强缓存的缓存存到了哪里?
对于这个问题,我们需要了解内存缓存(from memory cache)和硬盘缓存(from disk cache),如下:
• 内存缓存(from memory cache):内存缓存具有两个特点,分别是快速读取和时效性:
• 快速读取:内存缓存会将编译解析后的文件,直接存入该进程的内存中,占据该进程一定的内存资源,以方便下次运行使用时的快速读取。
• 时效性:一旦该进程关闭,则该进程的内存则会清空。
• 硬盘缓存(from disk cache):硬盘缓存则是直接将缓存写入硬盘文件中,读取缓存需要对该缓存存放的硬盘文件进行I/O操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢
在浏览器中,浏览器会在js和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取(from memory cache);而css文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。
协商缓存:
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:
协商缓存成功:
协商缓存失败:
可以看到,在协商缓存中有一个重要的数据,就是获取缓存数据的标识。 进入协商缓存后,浏览器在请求头携带相应的标识,来向服务器发送请求,有服务器决定是否使用缓存。 缓存的标识有两种,分别是:last- modified和etag。
last- modified最后修改时间。在浏览器第一次给服务器发请求后,服务器会把这个字段放在响应头。浏览器再次请求的的时候会在请求头中携带,If-Modified-Since这个字段,也就是服务器传来的最后修改的时间。服务器拿到这个字段会和last- modified字段进行比对,如果请求头中的这个时间小于最后修改时间,说明这个资源已经修改过了,就会返回新的资源和http请求流程一样,如果不是的话就会返回304状态吗,告诉浏览器直接用缓存资源。
etag是服务器根据当前文件的内容,给文件生成的唯一标识,只要里面的内容有改动,这个值就会变。服务器通过响应头把这个值给浏览器。 浏览器接收到ETag的值,会在下次请求时,将这个值作为If-None-Match这个字段的内容,并放到请求头中,然后发给服务器。 服务器接收到If-None-Match后,会跟服务器上该资源的ETag进行比对:
• 如果两者不一样,说明要更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
• 否则返回304,告诉浏览器直接用缓存。
两者对比
1. 在精准度上,ETag优于Last-Modified。优于 ETag 是按照内容给资源上标识,因此能准确感知资源的变化。而 Last-Modified 就不一样了,它在一些特殊的情况并不能准确感知资源变化,主要有两种情况:
• 编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效。
• Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了。
2. 在性能上,Last-Modified优于ETag,也很简单理解,Last-Modified仅仅只是记录一个时间点,而 Etag需要根据文件的具体内容生成哈希值。
另外,如果两种方式都支持的话,服务器会优先考虑ETag。