浏览器缓存与CDN缓存详解
浏览器缓存也叫做本地缓存, CDN缓存也可以称为共享缓存.
浏览器缓存tips
浏览器请求一个URL后, 再次请求就默认从本地缓存拿数据了(根据不同的用户行为, 可以有200 from disk
和304
两种状态码), 如果在请求URL加上参数或变化原来的参数, 那么会绕过本地缓存(200 from disk
)和协商缓存(304
), 直接从CDN缓存服务器获取文件, 返回200
状态码, 如果CDN缓存服务器设置的缓存key忽略参数, 并且CDN缓存文件还没有过期, 那么CDN并不会回源.
服务器端不设置缓存策略的情况
服务器端(CDN或源站)如果没有设置客户端缓存时间的策略(即响应头无expires
或cache-control
之类的控制缓存的字段), 不同的浏览器有不同的默认缓存时间.
比如IE浏览器的默认缓存时间就是一个session
的时间, 即如果用户打开一个新的IE窗口, 就会从服务器端获取新文件了.
Firefox浏览器的默认缓存时间依赖于last-modified
响应头, 缓存时间为文件上一次修改时间距离当前时间的差比10的结果: 默认缓存时间=(当前时间戳-文件上一次修改时间的时间戳)/10
.
用户使用ctrl+f5
进行强制刷新并不会促使CDN服务器回源获取新文件, 只是跳过浏览器本地缓存和协商缓存, 从CDN缓存服务器获取CDN的缓存文件而已.
只有当CDN的缓存文件过期或者手动清除CDN缓存或者因为LRU
策略被CDN服务器自动删除, CDN才会回源获取最新文件.
200 from memory cache
:
不访问服务器, 从内存中读取缓存. 此时的数据是缓存到内存中的, 当关闭浏览器后数据将不存在.
200 from disk cache
:
不访问服务器, 从磁盘中读取缓存, 当关闭浏览器后数据还是存在.
304 Not Modified
:
访问服务器, 发现数据没有更新, 服务器返回此状态码, 然后从本地缓存中读取数据.
如果浏览器请求头中既没有if-modified-since
请求头, 又没有if-none-match
请求头, 那么CDN缓存文件过期后, CDN将无法304
验证回源, 源站直接200
响应给CDN.
源站设置过期时间的几种情况
源站的响应头一般都会经过CDN传递给浏览器, 除非在CDN上用新的头覆盖.
源站设置
cache-control:max-age=600
浏览器会缓存文件, 后退前进、新打开窗口在地址栏打开链接均为
200 from disk
, 不会从服务端验证(304
), 除非本地缓存过期, 或者F5、ctrl+f5.CDN会缓存文件.
当源站设置5m过期, 生效后马上又变更为10m
浏览器缓存将一直按照5m, 即使CDN缓存文件过期(文件内容不变的情况下)也是按照5m, 除非将CDN原有缓存文件删除;
CDN缓存先是按5m, 过期后将按照10m.
源站设置
cache-control:max-age=0
时浏览器会缓存文件, 后退或前进都为
200 from disk
, 新打开窗口在地址栏打开链接, 先要去服务端协商验证文件是否已更新(304
).CDN会缓存文件, 但是每次请求过来都会去源站验证文件是否过期, 若未过期, 则源站返回304.
如果源站设置
cache-control:no-cache
时, 如果源是Nginx, 即expires -1
;浏览器会缓存文件, 后退前进
200 from disk
, 新打开窗口在地址栏打开链接, 先要去服务端协商验证文件是否已更新(304
).CDN将不缓存.
源站的Nginx设置
expires epoch
;浏览器会缓存, 后退前进可以看到
200 from disk
, 但是新打开窗口在地址栏打开链接则不验证缓存, 直接从服务端获取新数据, 服务端返回200
.CDN不缓存.
源站设置
cache-control:no-store
浏览器不会缓存, 后退、前进、新窗口打开等操作均要向服务端获取新数据, 服务端均返回200.
CDN不缓存.
源站设置
cache-control:max-age=10,s-maxage=1000;
表示设置CDN缓存1000秒, 浏览器缓存10秒.
浏览器将缓存10s,
s-maxage
对浏览器无效;如果源站只设置
s-maxage
, 那么CDN将按照这个缓存, 浏览器将按照自身默认缓存.CDN缓存1000s,
s-maxage
优先与max-age
.
CDN缓存tips
CDN上缓存文件的过期时间设置的3种情况
源站配置缓存时间
用户在CDN控制台进行缓存策略的具体配置
CDN有自己的默认缓存时间策略:
一般只有在用户既没有在源站上配置缓存时间, 又没有在CDN控制台配置的时候, CDN默认缓存策略才会生效, 不同的厂商有不同的策略.
拿阿里云CDN举例, 默认缓存时间是当前时间减去源站响应的
last-modified
头时间再乘以0.1
, 有取值限制, 最大值3600秒, 最小值10秒, 如果源站没有响应last-modified
头, 但是有etag
头, 则将默认缓存时间设置为10秒, 如果last-modified
和etag
头都没有, 则认为是动态内容, 将默认缓存时间设置为0, 即不缓存, 每次都回源.
以上3中情况, CDN一般遵循的优先级为2>1>3.
如果CDN变更缓存时间策略, 对于已经缓存的文件来说没有效果, 只有当已缓存文件过期或者手动清理已缓存文件后, 新的缓存时间策略才会对这些文件生效.
如果CDN没有该缓存文件, 则回源获取, 源站返回给CDN200
状态码, CDN表现为MISS
, 返回浏览器200
或304
.
如果CDN有该缓存文件并且没有过期, CDN表现为HIT
, 返回浏览器200
或304
.
如果CDN缓存文件过期, 则回源获取, CDN表现为EXPIRED
. CDN回源的请求头会带上if-modified-since
头:
- 当源站该文件没有变更, 则源站返回
304
状态码给CDN服务器, 此时CDN服务器会继续使用CDN原有缓存文件并把该缓存文件过期时间增加为源站配置的秒数或者CDN配置的秒数, 源站优先. CDN返回给浏览器304
或200
. - 当源站该文件已经更新, 则源站返回
200
状态码给CDN服务器, CDN更新缓存文件, 返回给浏览器200
.
以上CDN返回给浏览器的状态码解读:
200
: (ctrl+f5强制刷新、浏览器本地没有缓存、浏览器本地缓存过期并且到CDN进行对比后发现文件已经更新)304
: (f5刷新、浏览器本地缓存过期并且到CDN进行对比后发现文件没有更新)
关于缓存刷新
URL刷新
是指强制将CDN缓存的某个文件设置为已过期, 这样浏览器再请求过来的时候CDN就会回源去验证文件是否更新了, 更新了则取过来, 没更新则继续使用CDN原有的缓存文件并行使原有的缓存时间策略. 刷新缓存并不是删除缓存, 只是让CDN下次响应用户之前要先去源站验证文件是否为最新的.
目录刷新
是指强制将CDN缓存的某个目录下的文件均设置为过期, 本质和URL刷新是一致的, 目录刷新可以理解为批量做URL刷新.
缓存服务器行为与浏览器行为示意图
注意: 本图是在阿里云官方文档的原图基础上改进的, 我觉得阿里云的原图貌似有疏漏之处, 故重新画了一个. 阿里云原图如下: