今天被一个后端同学给问住了,为什么200状态码后面有一个from memary cache?一时竟然答不上来。为了彻底搞懂浏览器缓存,决定深入研究下。本次以chrome浏览器为例:
浏览器缓存分为两类:
1.强制缓存
2.协商缓存:也有称作“对比缓存”
首先强制缓存和协商缓存,都是指HTTP的缓存--即发生在应用层
强制缓存:
用户发送的请求,直接从客户端缓存中获取,不发送请求到服务器,不与服务器发生交互行为
协商缓存:
用户发送的请求,发送到服务器后,由服务器判定是否从缓存中获取资源
共同点:强制缓存和协商缓存,缓存都存在客户端。
不同点:协商缓存需要与服务器交互。
具体看下这两种缓存怎么实现:
什么是客户端缓存?
所谓“客户端缓存”就是指客户端将网络资源保存在用户设备中,可能保存在你的硬盘中,内存中等等等,下次浏览同一个资源时,不再从网络下载,实则是客户端从你的设备中获取的,不同浏览器缓存文件的地址也不尽相同。
以chrome浏览器为例:查看缓存
1.在chrome中输入chrome://version能看到浏览器的大部分信息如图:
复制出个人资料路径file:///C:/Users/Administrator/AppData/Local/Google/Chrome/,去掉后面的User,因为带上User可能打不开,因为你的数据在user data下面如图:
点击User Data
点击Default
cache缓存文件所在位置。当前缓存文件的URL列表,点击url可以看到对应的缓存文件内容,包括类型 编码 过期时间等概要信息,以及文件内容等具体信息,以二进制方式显示。
接下来我是使用chromecacheview查看缓存。
工具已经到位,接下验证缓存
验证缓存:
打开百度,ctrl+shift+I或者F12或者鼠标右键-检查,打开开发者模式,不勾选disable-cache选项。
刷新网页可以看到from memory cache(红框内)表示从缓存中获取的文件,打开chromeViewCache工具ctrl+f搜索bd_logo1.png
红色框内的就是本地缓存的bd_logo1.png的信息。也就是服务端返回给我们的response header信息。
前面提到了强制缓存和协商缓存:
图中expires和Cache-Control两个字段控制强制缓存。
介绍一下这个两个字段:
expires缓存原理:Http1.0 中的标准,表明过期时间,注意此处的时间都是指的是服务器的时间。
1. 浏览器第一次请求资源,浏览求返回资源的同时会在response header里面添加Expires。
2. 浏览器请求到资源时,会一同把资源和Expires缓存起来。
3. 浏览器再次请求同一个资源时,会先从浏览器缓存中获取,然后用客户端时间和缓存2步骤里缓存的expires作比较。小于缓存的expires表示使用缓存,否则从服务器获取。
4. 缓存过期也就是客户端时间大于expires,会再次从服务器获取资源,并且更新expires。
5. expires是http1.0的产物,已经过时。由于客户端时间可以随意修改,缓存容易出现问题。所以在http1.1之中使用了相对时间,cache-control: max-age=1000(注意单位是秒)
Cache-Control的缓存原理:
cache-control属性值:
max-age: 设置缓存的最大的有效时间,单位为秒(s)。max-age会覆盖掉Expires
s-maxage: 只用于共享缓存,比如CDN缓存(s -> share)。与max-age 的区别是:max-age用于普通缓存,而s-maxage用于代理缓存。如果存在s-maxage,则会覆盖max-age 和 Expires.
public:响应会被缓存,并且在多用户间共享。默认是public。
private: 响应只作为私有的缓存,不能在用户间共享。如果要求HTTP认证,响应会自动设置为private。
no-cache: 指定不缓存响应,表明资源不进行缓存。但是设置了no-cache之后并不代表浏览器不缓存,而是在缓存前要向服务器确认资源是否被更改。因此有的时候只设置no-cache防止缓存还是不够保险,还可以加上private指令,将过期时间设为过去的时间。
no-store: 绝对禁止缓存。
must-revalidate: 如果页面过期,则去服务器进行获取。
当浏览器命中强制缓存时:出现两种状态200 from disk cache和200 from memory cache.
from memory cache:字面理解是从内存中,其实也是字面的含义,这个资源是直接从内存中拿到的,不会请求服务器一般已经加载过该资源且缓存在了内存当中,当关闭该页面时,此资源就被内存释放掉了,再次重新打开相同页面时不会出现from memory cache的情况.
from disk cache:同上类似,此资源是从磁盘当中取出的,也是在已经在之前的某个时间加载过该资源,不会请求服务器但是此资源不会随着该页面的关闭而释放掉,因为是存在硬盘当中的,下次打开仍会from disk cache.
内存缓存(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: 表明请求的资源上次的修改时间,服务器返回的时间,在response header里。
If-Modified-Since:客户端会保留资源上次的修改时间,也就是Last-modified的时间。
Etag:资源的内容标识。(不唯一,通常为文件的md5或者一段hash值,只要保证写入和验证时的方法一致即可)。
If-None-Match: 客户端保留的资源内容标识。
浏览器将在第二次请求的header中加入If-Modified-Since(对应于Last-modified), 和If-None-Match(对应于Etag)。
通常情况下,如果同时发送 If-None-Match 、If-Modified-Since字段,服务器只要比较etag 的内容即可,当然具体处理方式,看服务器的约定规则。
Last-modified和If-Modified-Since:看下返回结果,设置Last-modified固定时间123456
看下第一请求:只有response有last-modify,请求头里并没有If-Modified-Since。因为是第一请求,浏览器并未缓存。
再次请求,Last-modified和If-Modified-Since一致,返回status: 304,告诉浏览器使用浏览器缓存。
Etag和If-None-Match:同上直接上Etag的代码:
第一次请求:response: Etag-123456。request:header并没If-None-Match,状态:200
第二次请求: