1、一个问题引出强缓存和协商缓存
1.1 问题背景
页面上一个离线工具下载:
- 离线工具下载到本地的名称是服务端在响应头content-disposition中定义的,规则是edge地址+端口;
- 单机版修改完edge端口(下载链接地址不变),下载的离线工具还是修改前的名称,接口返回304;
- 预期修改完端口,下载的离线工具是新edge端口的文件
问题原因:
修改完端口,不清理缓存的情况下,点击下载链接请求下载资源,其实这个文件只是文件名进行了变更,其内容不变,所以使用了缓存的文件,导致下载的文件名称未更新
1.2 强缓存和协商缓存
1.2.1 缓存
- 缓存优点:减少了不必要的数据传输,减少服务器的负担,提升网站性能,用户体验友好
- 缓存缺点:资源如果有更改但是客户端不及时更新会造成用户获取信息滞后
1.2.2 基本原理
1)浏览器在加载资源时,根据请求头的expires和cache-control判断是否命中强缓存,是则直接从缓存读取资源,不会发请求到服务器;
2)如果没有命中强缓存,浏览器一定会发送一个请求到服务器,通过last-modified和etag验证资源是否命中协商缓存,如果命中,服务器会将这个请求返回,但是不会返回这个资源的数据,依然是从缓存中读取资源;
3)如果前面两者都没有命中,直接从服务器加载资源
1.2.3 缓存分类
1) 强缓存
表现:服务端就在 response header 里面对该文件做了缓存配置,通过Expires
和 Cache-Control 两种响应头实现(Cache-Control优先Expires), 设置缓存的时间、缓存类型
|
2)协商缓存
强缓存就是给资源设置个过期时间,客户端每次请求资源时都会看是否过期;只有在过期才会去询问服务器。
当客户端请求该资源时发现资源过期了,这时就会去请求服务器,而这时候去请求服务器的这过程就可以设置协商缓存。
表现:协商缓存就是需要客户端和服务器两端进行交互的。服务端在response header里面设置 etag 和
last-modified, 下次请求时会带上这两个字段;设置如下:
协商缓存过程:
发请求-->看资源是否过期-->过期-->请求服务器-->服务器对比资源是否真的过期( 通过etag和
last-modified
)-->没过期-->返回304状态码-->客户端用缓存的老资源
发请求-->看资源是否过期-->过期-->请求服务器-->服务器对比资源是否真的过期-->过期-->返回200状态码,返回新的资源-->客户端如第一次接收该资源一样,记下它的cache-control中的etag、last-modified等
3)两者相同点
如果命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据;
4)两者不同点
强缓存不发请求到服务器,协商缓存会发请求到服务器。
注:为什么有了last-modified
还要有etag?
-
一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候并不希望客户端认为这个文件被修改了,而重新请求资源;
-
某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),if-modified-since能检查到的粒度是秒级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);
2、解决
给离线工具下载链接拼接时间戳来穿透协商缓存
改进:基于开始的问题,既然端口变化,那么就在下载链接后面拼接edge端口来穿透缓存,只有端口变化的时候才穿透,用时间戳则是每次都穿透。