浏览器缓存

623 阅读6分钟

由于本周因为相关缓存(cdn缓存和浏览器缓存)问题,导致部分页面数据出现点异常(数据显示之前的旧数据),因此打算去验证下,加深理解。

1、浏览器缓存:

  • 浏览器缓存主要是指http缓存,当客户端向服务器请求资源时,会优先选择浏览器缓存。如果浏览器有存在“要请求资源”的副本,就可以直接从浏览器缓存中提取,而不用从服务器获取这个资源。
  • 一般http缓存能缓存get请求响应的资源,通常指Web资源(html页面、图片、js、css等)
  • http缓存都是从第二次请求开始的。第一次请求资源,服务器返回的响应头上会有缓存参数设置。通过第二次请求资源时,浏览器会通过这些参数自动判断是否从缓存读取
    • 首先会判断是否是强缓存,请求直接返回200
    • 如果没有强缓存,则判断是否命中协商缓存,如果命中返回304
    • 如果两个都没有命中,返回新资源)
  • 使用express服务器的静态服务器,去做对应相关的检验处理。
express.static(root, [options]) //静态资源设置
//通过对于额外参数options修改,
//可以设置请求对应静态资源的缓存参数。
//其中与缓存相关参数有etag,cacheControl,lastModified,maxAge,setHeaders

在public文件夹下,新增个other.html文件,javascripts文件夹新增other.js,由other.html引用。然后设置静态资源,默认不使用缓存:

app.use(express.static(path.join(__dirname, 'public'), {
    etag: false,
    cacheControl: false,
    lastModified: false
}));

结果如图所示,基本响应是200,资源每次都是从服务器获取。

image.png

2、http请求示意图

首次请求流程图

image.png 再次请求流程图

image.png

3、强缓存

  • 强缓存是不需要发送http请求
  • 强缓存在http1.0,是由Expires控制
app.use(express.static(path.join(__dirname, 'public'), {
    etag: false,
    cacheControl: false,
    lastModified: false,
    setHeaders: function (res) {
        const time = new Date(new Date().getTime() + 30 * 1000);
        res.append("Expires", time.toGMTString())//设置30s过期日期
    }
}));

如下图所示,第一次请求,会从服务器读取,在过期日前之前,重新请求,发现后台服务器没有other.js的请求,且浏览器客户端请求是从内存缓存中读取。

image.png 注意:由于服务器时间与浏览器时间可能不一致,导致服务器返回的过期日期可能存在不准确情况。

  • 强缓存在http1.1,是由Cache-Control控制
app.use(express.static(path.join(__dirname, 'public'), {
    etag: false,
    //cacheControl: false,//启用cacheControl
    maxAge: 10000,//设置10s过期
    lastModified: false,
    setHeaders: function (res) {
        const time = new Date(new Date().getTime() + 30 * 1000);
        res.append("Expires", time.toGMTString())
    }
}));

如下图所示,当Cache-ControlExpires同时存在,优先由Cache-Control决定。

image.png image.png 注意:public 中主要参数由

public参数使用
public客户端和代理服务器都可以缓存。因为一个请求可能要经过不同的`代理服务器`最后才到达目标服务器,那么结果就是不仅仅浏览器可以缓存数据,中间的任何代理节点都可以进行缓存
private只有浏览器能缓存了,中间的代理服务器不能缓存
no-cache跳过当前的强缓存,发送HTTP请求,即直接进入`协商缓存阶段
no-store非常粗暴,不进行任何形式的缓存
s-maxage这和`max-age`长得比较像,但是区别在于s-maxage是针对代理服务器的缓存时间。

4、协商缓存

  • 强缓存失效后,浏览器会根据请求头中相应的标识向服务器请求,服务器根据这个标识来决定是否需要使用浏览器缓存。这个标识分为两种Last-Modified和 ETag
  • Last-Modified
app.use(express.static(path.join(__dirname, 'public'), {
    etag: false,
    //cacheControl: false,
    maxAge: 10000,
    //lastModified: false,
    setHeaders: function (res) {
        const time = new Date(new Date().getTime() + 30 * 1000);
        res.append("Expires", time.toGMTString())
        res.append("Cache-control", "no-cache")
    }
}));

即最后修改时间。在浏览器第一次给服务器发送请求后,服务器会在响应头中加上这个字段。 浏览器接收到后,如果再次请求,会在请求头中携带If-Modified-Since字段,这个字段的值也就是服务器传来的最后修改时间。服务器拿到请求头中的If-Modified-Since的字段后,其实会和这个服务器中该资源的最后修改时间对比:

-   如果请求头中的这个值小于最后修改时间,说明是时候更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
-   否则返回304,告诉浏览器直接用缓存。

image.png 第一次请求,如图所示:

image.png

第二次请求,如图所示:

image.png 修改文件后,在请求,会发现服务器上文件的时间不一样了,从而重新请求服务器资源。

注意:Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了

  • ETag
app.use(express.static(path.join(__dirname, 'public'), {
    //etag: false,
    //cacheControl: false,
    //maxAge: 10000,
    lastModified: false,
    setHeaders: function (res) {
        const time = new Date(new Date().getTime() + 30 * 1000);
        res.append("Expires", time.toGMTString())
        res.append("Cache-control", "no-cache")
    }
}));

ETag是服务器根据当前文件的内容,给文件生成的唯一标识,只要里面内容发生改变,这个值就会不一样,服务器通过响应头把这个值给浏览器。浏览器通过这个ETag,再下次一次请求时候,把这个值作为If-None-Match这个字段的内容,并放到请求头中,然后发给服务器。 服务器接收到If-None-Match后,会跟服务器上该资源的ETag进行比对:

-   如果两者不一样,说明要更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
-   否则返回304,告诉浏览器直接用缓存。

第一次请求:

image.png

第二次请求:

image.png 修改内容后,会发现重新请求服务端:

image.png 注意:ETag优先级高于Last-ModifiedETag(针对于文件的内容生成的哈希值)性能会低于Last-Modified(通过文件编辑的时间)

5、缓存存储位置

缓存存储位置含义
Service Worker主要用于离线缓存,无法访问浏览器的dom
Memory Cache 内存缓存,从效率上讲它是最快的。但是从存活时间来讲又是最短的,当渲染进程结束后,内存缓存也就不存在了(比较小的文件)
Disk Cache 磁盘中的缓存,从存取效率上讲是比内存缓存慢的,但是他的优势在于存储容量和存储时长(内存使用率高情况,或者文件比较大情况使用)
Push Cache 推送缓存

6、缓存好处

  1. 减少了冗余的数据传输,节省了网费。
  2. 缓解了服务器的压力, 大大提高了网站的性能
  3. 加快了客户端加载网页的速度

7、不使用缓存操作

1、使用ctrl+F5 强制刷新,会不使用强缓存和协商缓存

2、通过浏览器设置,停用缓存,每次都是从服务器获取最新数据

3、在强缓存的日期未过期,不需要从缓存数据中获取,可以在url后面增加时间戳等

参考文献:

浏览器灵魂之问

express