对于浏览器缓存的一点理解

以下设置是在chrome浏览器中验证的:

html设置过期
<meta http-equiv="Cache-control" content="max-age=1">
1s后过期,所以每次都会加载新的html,新打开标签后,都不用刷新
<meta http-equiv="expires" content="0">
不起作用
<meta http-equiv="expires" content="1">
有用

http请求分为文件和一般请求,html中的<script></script>就是请求文件,ajax、xhr等都是命令请求

先分析html文件的缓存机制
通过fiddler查看浏览器发起的的request,有如下两个字段
If-None-Match: W/"5c7f40d9-f61"
If-Modified-Since: Wed, 06 Mar 2019 03:39:05 GMT
再看reponse,有如下两个字段
Last-Modified: Wed, 06 Mar 2019 03:39:26 GMT
ETag: W/"5c7f40ee-f60"
这里If-None-Match对应ETag,If-Modified-Since对应Last-Modified
这里的值不一样,所以返回的数据是整个html文件,

修改html文件刷新几次再看fiddler,发现If-None-Match对应ETag,If-Modified-Since对应Last-Modified的值匹配上了,所以返回数据是空的,也就是只有一个header,没有body,而请求状态码也变为304了,304表示Not Modify,也就是从header中发现数据没改变,就直接从浏览器缓存中读取了。

再来分析js文件。
一开始访问没访问过的url时,js是直接被下载了的。但是后来即使改动了js文件中的内容,从开发者工具->network->js->4.js(也就是我html中用<script>标签请求的文件)->右键open in source panel,发现里面的代码不是我修改过的,请求返回结果是200 from memory cache。Fiddler中根本看不到这次js的请求,也就是直接从浏览器缓存中请求上次缓存的js文件。
这个时候即使在html中加meta标签设置页面过期时间为下一秒,刷新后在chrome浏览器中也不会重新加载js文件,这就令人恶心了。于是想想也是,毕竟url也没变。所以每次改动了js后最好也修改js的名称,比如加个版本号之类的,这样html中请求的js文件的名字也得改,也就是加载了最新的html后,发现html中需要的js文件在本地缓存中不存在。于是就会重新向服务器发出请求。这也是为什么我们引用cdn中的多个js工具库会带上版本号或者日期的原因之一。修改名字后,浏览器会重新加载js,再下次发现js文件名没改,也就是url没变,于是又会从缓存中读取。document.write('<script src="a.js?random="'+Math.random()+'><\/script>');这种方式可以让每次加载最新的a.js,但是浏览器好不容易给了我们缓存的机制用来加速加载页面,我们还投机取巧的降低效率,实在太对不起浏览器了。

再来分析http命令请求。
我们的命令请求一般用aja、xhr等方式发起,再用Fiddler查看请求,里面根本就没有If-None-Match和If-Modified-Since字段,也就是这种命令请求被ajax等封装为没有缓存对比的请求,而浏览器将html中的<script>标签解析为需要缓存对比的请求,于是加上If-None-Match和If-Modified-Since字段。

再来分析所谓的缓存。
着重讲一下文件的缓存,因为如上所述命令请求虽然也是http请求,但是没有If-None-Match和If-Modified-Since字段,所以不会被缓存,于是浏览器的缓存就应该是针对文件的了。

第一次请求
客户端请求浏览器缓存
发现没有缓存
向服务器请求数据
服务器返回数据
客户端将返回的数据存入缓存

非第一次请求:强制缓存
客户端请求浏览器缓存
有缓存,且未失效,则直接返回缓存数据
有缓存,但已失效,则向服务器请求数据,然后将返回数据缓存

非第一次请求:对比缓存
客户端请求浏览器缓存
浏览器缓存返回缓存标识
客户端请求服务器端验证缓存标识
标识有效则返回本地缓存数据
标识失效则重新请求服务器数据,然后将返回数据缓存

服务器返回数据的时候会往header中加入字段,比如If-None-Match和If-Modified-Since字段,这是服务器行为,主要看后台如何设置。
header中加入的缓存相关的 字段共同构成本地浏览器对这段数据的缓存规则,缓存规则主要就是Cache-Control
客户端中Cache-Control指令
Cache-Control: max-age=<seconds>
Cache-Control: max-stale[=<seconds>]
Cache-Control: min-fresh=<seconds>
Cache-control: no-cache 
Cache-control: no-store
Cache-control: no-transform
Cache-control: only-if-cached
就是设置meta

服务器端Cache-Control指令
Cache-control: must-revalidate
Cache-control: no-cache
Cache-control: no-store
Cache-control: no-transform
Cache-control: public
Cache-control: private
Cache-control: proxy-revalidate
Cache-Control: max-age=<seconds>
Cache-control: s-maxage=<seconds>
就是设置header

协议中可以造成强制缓存的字段有:

Expires:有效时间
Cache-Control:该字段表示缓存最大有效时间,该时间是一个相对时间。
使用相对时间的话,即使本地时间与服务器时间不一致,也不会导致缓存失效。
下面列举一下Cache-Control的字段可以带的值:
max-age:即最大有效时间
no-cache:表示没有缓存,即告诉浏览器该资源并没有设置缓存
s-maxage:同max-age,但是仅用于共享缓存,如CDN缓存
public:多用户共享缓存,默认设置
private:不能够多用户共享,HTTP认证之后,字段会自动转换成private

协议中可以造成对比缓存的字段有:

Last-Modified:服务器告诉客户端,资源最后一次修改的时间。
If-Modified-Since:再次请求时,客户端请求头中带有该字段,服务器会将If-Modified-Since的值与Last-Modified字段值进行对比,
如果相等,则表示未修改,响应304状态码,告诉客户端可继续使用缓存;反之,则表示修改了,响应200状态码,返回数据。

Etag:服务器端生根据请求的文件生成该字段,在response中返回给客户端,
If-no-match:客户端请求时携带的字段,服务器端Etag字段与之进行比较。
如果相等,则表示未修改,响应304;反之,则表示已修改,响应200状态码,返回数据。

但是,但是,但是,chrome浏览器中验证发现:每次请求都会携带If-None-Match和If-Modified-Since字段,而直接从缓存中返回from memory cache,按理来说,这两个字段是用来进行对比缓存的,结果却是强制缓存的效果,十分令人不解

没有图文并茂,懒得截图,

至于from memory cache和from disk cache的区别,就是一个存在内存中,一个存在本地硬盘,对前端是无感。只是有的文件比较大存在disk中比较好,有的文件时解码了的图片比如base64,这种东西一般存在memory cache中。存在哪里取决于浏览器,对前端无感就不关心了

猜你喜欢

转载自blog.csdn.net/youyudexiaowangzi/article/details/88234008
今日推荐