前端优化 其三 http 缓存
我们每一次打开网页,都需要获取比如js、css、图像、字体等各种资源。如果每一次都从网络上下载,显示并不是一个理智的选择。http 缓存提供了一种机制,浏览器首次加载
网页时,会将页面资源存储在 HTTP缓存中。当浏览器下次访问该页面时,它可以在缓存中查找以前获取的资源并从磁盘检索它们,这通常比从网络上下载资源要快。合理的利用http 缓存,可以使你的网站再次被访问时的渲染速度大大提高。
cache-control
cache-control 是http1.1 协议中定义在header头里用来告诉浏览器和服务器对缓存机制的支持情况,通过给他设置不同的值来定义缓存策略。
常用的值如下:(详见:mdn cache-control)
- no-store 禁止缓存,每一次请求都向服务器重新获取资源
- no-cache 每次请求,服务器会验证缓存是否过期;若过期重新发送资源,否则使用本地
缓存 - public 表示该响应可以被任何中间(比如中间代理、CDN等)缓存。
- private 表示该响应专只能应用于游览器私有缓存
- max-age 设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。与Expires相反,时间是相对于请求的时间。
- s-maxage 覆盖max-age 或者 Expires 头,但是仅适用于共享缓存(比如各个代理、cdn),并且私有缓存中它被忽略。
使用缓存策略不应该是盲目的。
- 或者我们应该先想想该资源是不是应该被缓存,不缓存就 no-store。
- 如果这是一个应该缓存的信息,那么他是该private 还是public?
- 接下来我们还要给它设置 max-age, 告诉浏览器资源多久才会过期。
- 最后我们可能还需要给资源加一个版本标识ETAG
ETAG
ETag HTTP响应头是资源的特定版本的标识符。这可以让缓存更高效,并节省带宽,因为如果内容没有改变,Web服务器不需要发送完整的响应。而如果内容发生了变化,使用ETag有助于防止资源的同时更新相互覆盖(“空中碰撞”)。
对于无法从文件名或者链接上加指纹的资源。这往往很有用,例如 .html。
vary
Vary 是一个HTTP响应头部信息,它决定了对于未来的一个请求头,应该用一个缓存的回复(response)还是向源服务器请求一个新的回复。它被服务器用来表明在 content negotiation algorithm(内容协商算法,详见)中选择一个资源代表的时候应该使用哪些头部信息(headers).
有点饶,举个经典的例子:比较老的浏览器是不支持gzip压缩的,如果我们向旧的浏览器发送gzip后的资源,旧浏览器没有办法解压缩并显示,那么就会出问题。这样子的话我们就可能需要使用同一个url向不同的浏览器发送不同版本的资源。如果我们使用了cdn,很可能资源请求都不会到达资源服务器,直接从cdn缓存服务器上获取资源。那么,cdn缓存服务器就必须同时缓存gzip版本、未gzip版本,同时有一个机制告诉他,应该使用哪一个缓存版本。通过指定 vary:Accpet-Encoding header头,缓存浏览器根据http request header 头Accpet-Encoding来判断返回浏览器合适的版本。vary具体详见。
文件指纹
浏览器发出的所有 HTTP 请求会首先路由到浏览器缓存,以确认是否缓存了可用于满足请求的有效响应。如果有匹配的响应,则从缓存中读取响应,这样就避免了网络延迟和传送产生的流量费用。
现实中往往可能发生错误的资源被用户缓存,例如:粗心的设计师弄错了图片上的文字。但是该资源还有30天才能过期,那么我们有办法替换掉用户的资源吗?答案是否定的,没有办法。
好在我们可以通过更改资源的链接地址,来让浏览器认为是一个新的资源。例如:将资源a.css改成a.xadf2.css。可以通过webpack等前端构建工具方便的实现这些功能,并且都是全自动化的,不需要开发人员付出额外的工作。这样子的话,我们甚至可以将缓存时间设置为长久(max-age最大缓存时间是1年),大大提高缓存利用率。