前言
继续挖坑啦,这个也是上次面试和面试官说了很多的一个问题来着,然后我来好好重新研究研究,试着来了解一下浏览器以及和它相关的一些的缓存机制。因为是坑,所以也是缓慢更新的,如果有错误欢迎提出哦!
文章部分是小结于《WebKit技术内幕》这本书关于浏览器本地缓存的文字和尾部列出文章的内容,然后HTTP相关的知识主要是来自于《图解HTTP》这本书哦~
强缓存(本地)
关于浏览器的本地缓存,我都以谷歌浏览器为核心开始搜集资料+测试啦!
查看谷歌浏览器中的本地缓存资源只要输入下面的地址就可以:
chrome://cache
就可以看到本地缓存的文件,一个个URL排列,点开一个URL,就可以显示这个缓存的具体内容:
浏览器资源
常见的资源主要有:HTML、JavaScript、CSS、图片、SVG、CSS Shader、视频、音频和字幕、字体文件、XSL样式表。
浏览器资源可以分为两类:
- 主资源:HTML页面,或者下载项
- 派生资源:比如HTML页面中内嵌的图片或者脚本链接
在WebKit内核中,是用不同的类来表示它们,有一个公共父类叫做CachedResource
,也很好理解,就是缓存的资源
。由此对应的子类比如:CachedCSSStyleSheet
缓存的CSS样式表等等,以此类推。但是HTML比较特殊,它对应的类叫做CachedRawResource
。
资源加载器
WebKit有三种类型的加载器。
- 每种资源类型的特定加载器:只加载一种特定的资源,比如
imageLoader
、FontLoader
,当请求资源时,加载器来负责加载。 - 缓存机制的资源加载器:所有特定加载器通过它(
CachedResourceLoader
类)查找并插入缓存资源。 - 通用资源加载器:
ResourceLoader
类,WebKit需要从网络/文件系统获取资源的时候由它负责。
请求过程
浏览器在发起请求的时候,会先去获取缓存的信息,再来决定是否向服务器发起请求。
WebKit如果在资源池寻找资源:
- 找到了,就会拿出来用;
- 没找到,创建一个新的
CashedResource
子类对象,向服务器发送请求。收到资源后放入缓存中。(使用的是LRU
算法来进行资源池资源的替换)
浏览器是根据URL来判断不同的缓存内容
也就是假如有两个文件,虽然它们的文件可能是相同的,但只要URL不同,浏览器就不会认为是同一个,所以都会进行一次缓存。
实际操作一下,进入localhost
和127.0.0.1
来缓存一些东西:
这个meituce/images/logo.png
其实是同一张图,但是因为URL不一样,所以浏览器缓存了两次。
继续观察:
通过控制台可以看到资源主要有两种,而且对应文件类型不同,来源也不太一样,强缓存得到的状态码是200 OK:
- from memory cache(图片、脚本)
- from disk cache(css)
内存缓存&磁盘缓存
内存缓存 Memory Cache
放入内存中缓存,Webkit的内存缓存只是针对派生资源。
磁盘缓存 Disk Cache
放入磁盘中缓存,访问时不需要重新下载资源,直接从磁盘中获取。WebKit中也只能存储一些派生类资源。
存储形式为一个index.dat文件:URL + Response信息 + Content内容。
Response信息用于判断服务器上该Url的Content内容是否被修改。
这两者的区别是
退出浏览器进程时,内存缓存中的数据会被清空,而磁盘缓存的数据不会。
不严谨的实验:
这个网站只有HTML是没有被缓存的,所以可以证实,派生资源被缓存到其中。
单独输入一个在原网页中缓存过的图片来获取,发现它不是从磁盘内存缓存中来:
HTTP相关请求字段
expires
来源版本:HTTP 1.0
值:GMT格式的时间字符串
判断方法:如果发送的时间在这个时间之前,就从本地读取缓存。
expires: Sun, 27 May 2018 09:15:15 GMT
cache-control: max-age=?
来源版本:HTTP 1.1
值:cache-control操控缓存的工作指令,不同指令通过,
分隔开;其中指令max-age的值为一个数字,表示过期时间,单位是秒。
判断方法:如果根据时间和max-age算出已经是<=0了,就说明时间超过了,需要从服务器去读取。
cache-control: max-age=691200
如果cache-control与expires同时存在的话,cache-control的优先级高于expires
协商缓存(经过服务器)
这部分的内容就和HTTP的内容相关联了,主要是几个字段。
if-XXX这种字段称为条件匹配,即只有当结果为真时,服务器才会执行请求。
协商缓存成功后得到的状态码是304 NOT MODIFIED
HTTP相关请求字段
if-Match / if-None-Match
来源版本:HTTP 1.1
这个要联系到一个响应字段Etag
,即服务器会一开始返回一个Etag
值,只有后面这个E-tag
作为if-Match
字段的值发送到服务器,服务器进行判断是否匹配,来确定是否过期。
若匹配不一致,返回412(Precondition Failed)状态码。
可以指定字段值为*
,这样只要资源存在,服务器就会忽略Etag
值。
If-Match: "bfc13a64729c4290ef5b2c2730249c88ca92d82d"
if-Modified-Since / if-Unmodified-Since
来源版本:HTTP 1.0
根据字面意思也可以知道,这是制定了一个时间,表示在这个时间后更改/未更改。
它可以根据Last-Modified
字段来确定是否符合要求。
If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
既然有if-Modified-Since,为何又有Etag和if-Match?
- 文件可能会被修改,但内容不改变(改变只是修改时间),而前者会再次重新获取。
- If-Modified-Since只能精确到秒。
- 某些服务器不能精确文件的最后修改时间。
缓存服务器
缓存服务器是代理服务器的一种,缓存服务器帮客户端转发资源的时候,自己也会保存一份。请求的资源如果已经被缓存,则直接返回。
其他补充
还可以在谷歌控制台的Network面板,选择Disable cache来禁止使用缓存。
推荐文章
由memoryCache和diskCache产生的浏览器缓存机制的思考
Web开发须知的浏览器内幕 缓存与存储篇
memoryCache和diskCache流程详解
http协商缓存VS强缓存