Skip to content
On this page

前言

作为一个合格的前端工程师,且以大厂为目标的程序猿,浏览器的相关工作原理使我们进行性能优化的基石。必须牢牢掌握这才能对瞬息万变的实际场景,针对性地给出实际方案,而不是各种背诵(掘金上混脸熟)的开发'军规'和性能优化常见条例。这样很难真正发现问题所在。自己也得不到实质性的提升。

HTTP 缓存分为两种强缓存协商缓存。两者的作用都是加快资源获取,提升用户体验,减少网络连接,缓解服务器的压力。还有这里的缓存是指文件文件!!!并不是指平时后端从服务器拿出来的数据。

1.png

又到了看图说话的时候了,我们都知道我们请求文件是发送get请求,在发起的时候浏览器就回去找请求头是否开启了强缓存。没开启就直接进去弱缓存阶段了。如果开启了就回去比对强缓存的标志是否过期之类的,没有过期则直接读取缓存这时候状态码是200(实际上并没有发请求)!紧接着过期了,那就必须发送一个请求去服务器了。这就到了弱缓存阶段。这时候就会询问服务器我所请求的文件是否更新了如果没更新则会返回304告诉浏览器文件没有更新。更新了则返回200让浏览器缓存新的文件。

强缓存

不需要发送网络连接给服务器,直接读取本地的缓存。缓存可以从硬盘或者内存中。这是由浏览器决定的。但是强缓存是由ExpiresCache-controlPrage3 个属性来控制的。

Expires

Expires也就是过期时间,这里通常会设置一个时间戳Tue, 02 Jun 2020 04:12:42 GMT但是这个属性有严重的缺陷就是如果服务器时间跟本地时间不同的话(时区)这个字段就没有任何意义了。所以这个字段在http1.1是采用Cache-control来控制。Expires优先级最低

Cache-control

Cache-control这个属性是http1.1新增,在响应头和请求头中都可以设置。常见的属性有

  • max-age: 单位是秒,缓存时间计算方式是距离上一次发起时间的秒数,超过间隔的秒数缓存失效
  • no-cache: 禁止使用强缓存
  • no-store: 禁止使用缓存(包括协商缓存)
  • private: 专用于个人的缓存,中间代理,CDN 等不能缓存响应
  • public: 响应可以被中间代理、CDN 等缓存
  • must-revalidate: 在缓存过期前可以使用,过期后必须向服务器验证

Pragma

Pragma只有一个属性值就是no-cache,这个属性跟Cache-control中的no-cache一样就是不使用强缓存

验证环节

本文采用express作为服务端(主要KOA没有找到关闭弱缓存的方法....)还是太菜了

javascript
const express = require("express");
const app = express();
var options = {
  etag: false, // 禁用协商缓存
  lastModified: false, // 禁用协商缓存
  setHeaders: (res, path, stat) => {
    res.set("Cache-Control", "max-age=100"); // 强缓存超时时间为10秒
  },
};
app.use(express.static(__dirname + "/public", options));
app.listen(3000);

3.png

第一次加载服务端的响应头中加入了Cache-Control:max-age=100这个字段,也就是强缓存的时间为 100 秒

4.png

第二次加载(并不是刷新)可以明显看到http状态码中有(from disk cache)的字样。

加入Pragma后并把值设为no-cache后发现,尽管有max-age但是也会重新请求服务端加载文件。

协商缓存

当强缓存没有命中后,并且请求头中设置了If-Modified-Since或者If-None-Match的时候,就会去尝试命中协商缓存,命中后则会返回304状态,加载浏览器缓存,并且响应头会设置Last-Modified或者ETag属性

Last-Modified/If-Modified-Since

Last-Modified/If-Modified-Since两者都是代表文件的最后修改时间,在第一次请求的时候服务端会返回这个文件的最后修改时间到Last-Modified字段中。在客户端重新请求这个文件的时候会带上一次请求返回的Last-Modified字段的值添加到本次请求头中的If-Modified-Since中,服务端会比较If-Modified-SinceLast-Modified是否相同,相同则返回304读取浏览器缓存。

ETag/If-None-Match

ETag/If-None-Match的值是一串hash码,代表的是一个资源的标识符,当服务端的文件变化的时候,它的hash码会随之改变,通过请求头中的 If-None-Match 和当前文件的 hash 值进行比较,如果相等则表示命中协商缓存。ETag 又有强弱校验之分,如果 hash 码是以 "W/" 开头的一串字符串,说明此时协商缓存的校验是弱校验的,只有服务器上的文件差异(根据 ETag 计算方式来决定)达到能够触发 hash 值后缀变化的时候,才会真正地请求资源,否则返回 304 并加载浏览器缓存。