记一次http缓存优化

我们用http访问网站时,会先发起一个请求,之后服务器响应这个请求,在Chrome的开发者工具(按F12或右击选择检查)我们可以看到整个过程。

第一部分General,包含请求地址、请求方式,状态码,服务器地址以及Referrer策略。

第二部分是响应头,是服务器端返回的。

第三部分是请求头,是客户端发起的。

这次我们从两个角度来看看http的缓存:缓存控制和缓存校验。

缓存控制:控制缓存的开关,用于标识请求或访问中是否开启了缓存,使用了哪种缓存方式。

缓存校验:如何校验缓存,比如怎么定义缓存的有效期,怎么确保缓存是最新的。

缓存控制

Cache-Control的含义

可缓存性

属性名 含义
public http 请求返回的过程当中,在 cache-control 中设置这个值,代表 http 请求返回的内容所经过的任何路径当中(包括中间一些http代理服务器以及发出请求的客户端浏览器),都可以对返回内容进行缓存操作。
privte 代表只有发起请求的浏览器才可以进行缓存
no-cache 可以在本地进行缓存,但每次发请求时,都要向服务器进行验证,如果服务器允许,才能使用本地缓存。

到期

属性 含义
max-age= 缓存多少秒后过期,过期之后浏览器才会再次发送请求。
s-maxage= 浏览器基本用不到,会代替 max-age,但只有在代理服务器中才会生效。在代理服务器中,如果都设置了 max-age,s-maxage,还是会读取 s-maxage。
max-stale= 浏览器基本用不到,当 max-age 过期后,如果返回资源中有 max-stale 的设置。max-stale 是发起请求方主动携带的头,即使 max-age 过期,只要 max-stale 没过期,可以继续使用缓存资源,不需要重新请求。浏览器主动设置这个头,只有在发起端才有用。

重新验证

属性 含义
must-revalidate 浏览器可能会用到,如果 max-age 过期,需要重新发送请求,获取这部分数据,再来验证数据是否真的过期,而不能直接使用本地缓存。
proxy-revalidate 用在缓存服务器中,指定缓存服务器过期后,必须向源服务器重新请求,不能直接使用本地缓存。

其他

属性 含义
no-store 本地和代理服务器都不可以存储缓存,每次都要重新请求,拿到内容。
no-transform 主要是用在 proxy 服务器,不允许进行格式转换。

浏览器缓存

通过 Cache-Control 以及 max-age 设置,达到长缓存的效果。

启动服务器 node server.js,在 localhost:8888 打开,查看network,当设置 max-age 后,刷新页面,浏览器直接从缓存中进行读取,不去要再向服务器请求,达到缓存静态资源的目的。

存在的问题,服务端修改返回内容,客户端没有加载新的内容,因为请求 url 没变,浏览器会直接从缓存读取,不需要经过服务端验证,导致静态资源更新后,没有及时更新到客户端。

解决方案,打包静态资源时,根据内容进行 hash 计算,生成文件名的 hash 码。内容变,hash 码变,请求资源 url 变,浏览器重新请求加载资源,达到更新缓存的目的。

缓存校验

在缓存中,我们需要一个机制来验证缓存是否有效。比如服务器的资源更新了,客户端需要及时刷新缓存;又或者客户端的资源过了有效期,但服务器上的资源还是旧的,此时并不需要重新发送。缓存校验就是用来解决这些问题的,在http 1.1 中,我们主要关注下Last-Modified 和 etag 这两个字段。

验证头

Last-Modified

上次修改时间。

服务端在返回资源时,会将该资源的最后更改时间通过Last-Modified字段返回给客户端。客户端下次请求时通过If-Modified-Since或者If-Unmodified-Since带上Last-Modified,服务端检查该时间是否与服务器的最后修改时间一致:如果一致,则返回304状态码,不返回资源;如果不一致则返回200和修改后的资源,并带上新的时间。

Etag

数据签名,资源内容会对应有一个唯一的签名,如果资源数据更改,签名也会变。

单纯的以修改时间来判断还是有缺陷,比如文件的最后修改时间变了,但内容没变。对于这样的情况,我们可以使用etag来处理。

etag的方式是这样:服务器通过某个算法对资源进行计算,取得一串值(类似于文件的md5值),之后将该值通过etag返回给客户端,客户端下次请求时通过If-None-Match或If-Match带上该值,服务器对该值进行对比校验:如果一致则不要返回资源。

验证头的使用

服务器设置 Last-Modifed 和 Etag 的值,浏览器请求会携带这两个头,在请求头中,会有 If-Modified-since: Last-Modifed值 和 If-None-Match: Etag值。

这时 response 中是有内容的,这里希望服务器不返回实际的内容,只需要告诉浏览器直接读取缓存即可。通过在服务器端进行判断。

这时查看 respones 发现还是有内容,这个内容是 Chrome 浏览器 从缓存中读取显示出来的,服务器没有返回内容。

如何判断服务端通过验证,但是从缓存读取的呢,通过服务器设置 HTTP Code 304,Not Modified 表示资源没有修改,直接读缓存,这时就会忽略服务端返回的内容。

清除小程序webview缓存

1
<web-view src="{{fomalUrl}}></web-view>

由于webview跳到h5界面是单页面应用

  1. 按照网上的办法给跳转路径后面加时间戳,并没有什么用。。。
  2. 在测试和正式环境打包的时候,给css js加hash,也没什么用

解决办法:

1
2
3
4
5
<META HTTP-EQUIV="pragma" CONTENT="no-cache">

<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">

<META HTTP-EQUIV="expires" CONTENT="0">

在根目录的index.html头部加上上面几句就可以清除缓存了

参考

前端性能优化 —— 添加Expires头与Cache-control区别

浅谈http中的Cache-Control

http请求头If-Modified-Since & If-None-Match


记一次http缓存优化
https://thaneyang.github.io/2021/05/记一次http缓存优化.html
作者
ThaneYang
发布于
2021年5月15日
许可协议