前端浏览器缓存优化:提高网站访问速度的重要手段

背景

目前越来越多的网站和应用程序依赖于前端技术。在前端技术中,浏览器缓存是一项重要的优化技术,可以显著提高网站的性能和用户体验。通过利用浏览器缓存,可以减少页面请求次数,降低服务器的负载,提高网站的访问速度,从而提高用户的体验。

在本文中,我们将探讨前端浏览器缓存的优化技术以及它们的实现方式

如果您需要进一步的协助或有任何问题,请随时提问!希望这篇文章对大家有所帮助。

什么是浏览器缓存

浏览器缓存是指浏览器在第一次访问一个网页时,将页面的各种资源文件(如样式表、JavaScript文件、图片等)缓存到本地磁盘上。当用户再次访问该网页时,浏览器会先检查本地缓存是否存在对应的资源文件,如果存在未过期,就直接从本地加载资源文件,而不是重新下载。

浏览器缓存优化是一种可以显著提高网站性能的技术,因为它减少了网络请求次数,降低了服务器的负载,同时也缩短了用户等待页面加载的时间。

浏览器缓存机制

浏览器缓存位置

当我们访问页面后,再次刷新页面,打开浏览器开发者工具 Network,可以发现很多资源文件都来自缓存。例如:

或者:

浏览器缓存分为四个位置:

1、Memory Cache

内存缓存,将请求结果缓存到内存中,读取速度快。

Memory Cache是指浏览器在内存中缓存的一些静态资源,例如HTML、CSS、JavaScript文件等。由于内存读取速度非常快,因此浏览器将这些资源缓存在内存中,以便下次访问时能够更快地获取这些资源。缓存在内存中的资源可以非常快速地被访问和加载,但是内存空间非常有限,所以这些资源只会在浏览器打开期间保存。

2、Disk Memory

硬盘缓存,将请求结果缓存到硬盘中,读取速度相对慢。

Disk Cache 是指浏览器在磁盘中缓存的一些静态资源,例如HTML、CSS、JavaScript文件等。与 Memory Cache 不同,Disk Cache 中的资源可以被长时间保存,即使浏览器关闭后也可以再次访问。但是,由于磁盘读取速度相对内存较慢,所以从磁盘中读取缓存的资源会比从内存中读取慢一些。通常情况下,浏览器会根据 HTTP 响应头中的缓存控制信息来决定是否将数据缓存到硬盘中。

硬盘缓存比内存缓存读取速度慢,读取需要对硬盘进行I/O操作,会导致重新解析缓存内容,造成读取路的复杂。

我们常见最多的就是 Memory Cache 与 Disk Memory。

区别 Memory Cache Disk Memory
存储资源 一般脚本、图片、字体 一般非脚本css等
存储时效 进程关闭清除 不受进程关闭影响,可以缓存较长时间
存储空间
读取速度

CSS文件加载一次就可以渲染,不会频繁的读取,存储在Disk Cache;js脚本可能会随时会被执行,存储在Memory Cache,若存储在硬盘中,会因为I/O开销大导致浏览器失去响应。

3、Server Worker

可以让网站在用户离线时继续运行,并且可以控制页面的缓存。

Service Worker 是一种运行在后台的 JavaScript 脚本,可以控制网络请求和响应。Service Worker可以缓存页面中的资源,例如 HTML、CSS、JavaScript文件、图像、字体等,可以使网站在离线状态下仍能够访问。

与 Memory Cache和Disk Cache不同,Service Worker Cache是一种持久化的缓存,即使用户关闭浏览器后,这些缓存也可以被保留下来。

4、Push Cache

仅适用于HTTP/2,用于缓存推送的响应结果。

推送缓存,是HTTP/2的内容,并没有严格执行HTTP头部的缓存指令。在Server Worker、Memory Cache、Disk Cache都没有命中的时候,它会被使用。在Session中存在,Session结束就会被释放,缓存时间短暂。

总之,Memory Cache 和 Push Cache 缓存都是相对较短的缓存,一般只在浏览器当前打开的标签页中有效。而 Disk Cache 和 Service Worker 缓存则可以在用户关闭浏览器后仍然有效。

以下是将浏览器缓存位置四类的区别按照表格进行展示:

缓存位置 作用 存储时机 过期机制
内存缓存 临时存储,提高用户体验 tab页面关闭后自动清除 无过期机制,由浏览器自动控制
磁盘缓存 加快网页打开速度 长期存储,直到缓存满或过期 由服务器设置响应头进行控制
Service Worker 缓存 支持离线访问和更好的缓存控制 由开发者手动控制 由开发者手动控制
Push Cache 减少网络传输和服务器负载 由服务器设置响应头进行控制 由服务器设置响应头进行控制

说完浏览器缓存位置四类的区别,我们再来说一下prefetch cache 预取缓存

prefetch cache 预取缓存

预取缓存是在页面加载时自动预取相关资源,以便在用户需要时能够快速加载。它主要用于加速页面和资源的加载速度,减少用户等待的时间。

预取缓存的实现通常通过添加 link 标签来完成。通过标记prefetch实现预加载,被标记为 prefetch 的资源会在浏览器空闲的时间加载。例如,可以在页面的头部添加以下代码:

html 复制代码
<link rel="prefetch" href="https://example.com/image.jpg">

预取缓存(Prefetch Cache)与浏览器缓存位置四类有着一定的区别,下面是它们之间的主要区别:

区别 预取缓存 浏览器缓存位置四类
作用 加速页面和资源的加载速度 减少网络传输和服务器负载,提高用户体验
缓存位置 预取缓存中 内存缓存、磁盘缓存、HTTP 缓存、Service Worker 缓存
缓存内容 缓存页面和资源的 URL 缓存页面和资源的实际内容
控制方式 通过添加 link 标签来控制 通过 HTTP 头信息来控制

浏览器缓存分类

浏览器缓存分为强缓存和协商缓存两种。

强缓存

强缓存是指直接从缓存中读取资源,而不需要向服务器发送请求,一般通过设置响应头来实现。

常见响应头设置的缓存标识有 Cache-ControlExpires

Cache-Control字段用于控制缓存的行为,它可以设置多个指令,常用的有以下几个:

指令 作用
public 允许所有用户缓存
private 只允许私有缓存,比如浏览器缓存
no-cache 不直接使用缓存,需要先向服务器验证资源是否过期
no-store 不缓存资源

例如,设置强缓存的有效期为3600秒,可以添加如下的HTTP响应头:

arduino 复制代码
Cache-Control: max-age=3600

Expires字段用于设置资源的过期时间,它的值为一个GMT格式的日期时间字符串。如果当前时间在Expires字段的值之前,那么缓存资源就是有效的。

例如,设置缓存的过期时间为2024年1月1日,可以添加如下的HTTP响应头:

yaml 复制代码
Expires: Mon, 1 Jan 2024 00:00:00 GMT

协商缓存

协商缓存则是先向服务器发送请求,服务器根据请求头中的信息判断资源是否可以缓存,并返回相应的状态码和响应头信息,以告诉浏览器是否可以使用缓存。如果文件没有发生变化,则返回304状态码。

协商缓存可以通过设置HTTP响应头中的Last-ModifiedETag字段来实现。

Last-Modified字段用于记录资源的最后修改时间,它的值为一个GMT格式的日期时间字符串。当浏览器再次请求该资源时,会在请求头中添加If-Modified-Since字段,其值为上一次请求返回的Last-Modified字段的值。如果资源的最后修改时间比If-Modified-Since字段的值要新,那么服务器就返回最新的资源,否则返回304状态码。

例如,设置资源的最后修改时间为2022年1月1日,可以添加如下的HTTP响应头:

yaml 复制代码
Last-Modified: Fri, 1 Jan 2022 00:00:00 GMTyaml

ETag字段用于记录资源的唯一标识符,它的值可以是一个哈希值或者一个版本号。当浏览器再次请求该资源时,会在请求头中添加If-None-Match字段,其值为上一次请求返回的ETag字段的值。如果资源的唯一标识符和If-None-Match字段的值相同,那么服务器就返回304状态码,否则返回最新的资源。

例如,设置资源的唯一标识符为"abc123",可以添加如下的HTTP响应头:

vbnet 复制代码
ETag: "abc123"

强缓存和协商缓存区别

注意,强缓存和协商缓存是HTTP协议中的两种不同的缓存机制,它们的具体实现方式可能因浏览器和服务器的不同而有所差异。

特征 强缓存 协商缓存
缓存判断位置 客户端浏览器 服务端
缓存命中时机 在第一次请求资源时,服务器将资源返回给客户端,并在响应头中添加缓存标识 在第一次请求资源时,服务器将资源返回给客户端,并在响应头中添加缓存标识,客户端在后续请求时将该标识带回给服务器,服务器根据标识判断是否命中缓存
命中缓存的响应码 200(from cache) 304(not modified)
缓存过期时间 可以通过设置Expires或Cache-Control响应头来指定 可以通过设置Last-Modified或Etag响应头来指定
缓存优先级
缓存机制 客户端控制 服务器控制

强缓存和协商缓存的区别,也说明了两者在浏览器缓存机制下也存在着不同,见下面浏览器缓存过程

浏览器缓存过程(很重要

搞明白这个,基本就摸清了浏览器缓存的机制。

浏览器缓存的过程一般分为以下几步:

  1. 浏览器第一次(或禁止缓存)请求加载资源,向服务端发送请求,服务器返回200,浏览器将最新的资源从服务器下载。如果服务端配置了 Headers,服务端会在请求返回时,随 Response Headers 一起返回给浏览器,浏览器会将 Response Headers 与返回时间一起缓存。
  2. 浏览器再次发起请求加载资源的时候,会比较与上一次下载资源的时间差,如果没有超过 Cache-Control 设置的 max-age ,则没有过期,此时就会从本地缓存读取资源。如果浏览器不支持 HTTP1.1,那么则会用 Expires 判断是否过期(这一过程称为强缓存)。
  3. 如果对比时间发现已过期,或者没有强缓存标识。服务器则会查看请求的 Headers 中 If-None-Match 的值,与该请求资源的 Etag 做比较,如果相同则代表资源没有发生改变,返回304。否则,直接返回新的资源,并返回200(这一过程称为协商缓存)。
  4. 如果服务器收到的请求 Headers 中,没有 Etag 值,则会读取 If-Modified-Since 和被请求文件的最后修改时间做对比,如果相同则代表没有发生改变,返回304。否则,直接返回新的资源,并返回200(这一过程称为协商缓存)。

下载资源的同时,在 Response Headers 中会携带 Etag (资源的唯一标识,资源发生改变,标识也随之改变)、Last-Modified(资源文件最后一次更改时间),而浏览器会把这两个保存下来。

而向服务端发送资源请求时,在 Request Headers 中,会把浏览器下载资源时缓存的 ETag 放到 If-None-Match 中,把保存的 Last-Modified 放到 If-Modified-Since 中发给服务端。

Etag -> If-None-Match

Last-Modified -> If-Modified-Since

DNS缓存与CDN缓存

除了浏览器缓存以外,还有DNS缓存和CDN缓存也可以优化网站的访问速度。

DNS缓存

DNS缓存是指浏览器在访问网站时,会将网站的 DNS 解析结果缓存到本地缓存中。

这样下次访问同一域名时,就可以直接使用本地缓存中的解析结果,而不需要重新进行 DNS 解析,从而加快了网站的访问速度。

CDN缓存

CDN 缓存是指使用 CDN 服务提供商提供的缓存机制,将网站的静态资源文件缓存到CDN节点上,以加速用户访问网站的速度。

用户下次再访问同一资源时,就可以直接使用CDN节点中的缓存文件,而不需要重新下载文件,从而提高网站的访问速度。

缓存优化方案

为了更好地利用浏览器缓存,提高网站的访问速度,我们可以采取以下缓存优化方案:

打包构建优化

在打包构建时,可以为静态资源文件添加 Hash 值或版本号,以便在文件内容变化时,可以强制浏览器重新加载新的文件。这样可以避免用户访问旧版本的文件,提高网站的访问速度。

例如,可以将样式表的 URL 修改版本号为:

ini 复制代码
<link rel="stylesheet" href="style.css?v=1.0">

当样式表的内容发生变化时,只需要将 URL 中的版本号修改为 2.0,浏览器就会认为是一个新的文件,重新下载并缓存。

相比于版本号,Hash 更为优秀。

现在很多打包工具都默认配置了 Hash。其原理在于,只要文件内容不变,文件名就不会变,这样大大提高了静态文件缓存的使用寿命。

但是问题也就出现了,以上的这种优化,大都用于除 html 文件外的其它静态资源文件(比如说以.js、.png...后缀结尾的文件),而客户端在访问页面时,浏览器加载 html 是不会带上所谓的 Hash 或者版本号的。这就导致了很多时候服务端资源文件更新了,但是客户端由于缓存,还在使用之前老 html 文件加载的静态资源。那么这个问题如何处理呢?

首先,我们可以使用上面缓存过程 提到的强缓存协商缓存,当服务端文件更新后,浏览器借用 Headers 标识来实现加载新资源。

另外,也可以通过设置 HTML 的 cache-control 实现。

html 复制代码
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="Cache-Control" content="no-cache" />

这样可以告诉浏览器不要缓存 HTML 文件,从而确保每次访问页面时都会重新请求最新的 HTML 文件。但是需要注意的是,有些情况下这个方案会被服务端默认配置所覆盖

我们还可以尝试添加 Etag,但是这个方案有时有效果,有时没有效果。(实际中,某云厂家的资源未返回Etag)

因此,我们需要综合考虑,选择最适合项目的方案。在我的调试中,最稳妥的方案是:设置浏览器不缓存 HTML

设置浏览器不缓存,每次浏览器刷新都会拉取最新的 HTML 文件。而当 HTML 中加载的资源文件路径发生变化时,浏览器就会直接拉取最新的资源文件。但是这个方案也需要注意:由于每次都会请求新的 HTML,所以 HTML 只能加载资源路径,不能加载大量代码,否则页面渲染速度会变慢。

具体实现方案是,在服务端的 Nginx 中添加禁止缓存的 Header 配置,切记只对 HTML 设置禁止缓存。配置如下:

bash 复制代码
location / { 
    if ($request_filename ~* .*.(?:htm|html)$) {
        add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
    }
}

通过上述方案的使用,可以有效解决浏览器缓存资源带来的问题,确保用户访问的始终都是最新资源。

部署nginx代理配置(很有效

在处理前端浏览器缓存优化的过程中,我发现了一个问题:由于我们的项目使用微前端技术搭建,许多项目资源都在同一域名下,路径不同。如果按照之前的方式直接在 location 配置中添加 Header 缓存控制,所有项目的 HTML 都将被修改。

为了解决这个问题,我对路径进行了正则处理:

nginx 复制代码
location ~ ^/static/(admin1|admin2|admin3)/ { 
    if ($request_filename ~* .*.(?:htm|html)$) {
        add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
    }
}

admin1|admin2|admin3 是各应用项目路径,可以添加和修改。

在上面的配置中,我使用了以下响应头:

  • private 只能被终端用户的浏览器缓存,不允许 CDN 等对其缓存。会影响到 CDN 缓存命中率,但在量较小的情况下,也可以禁用。
  • no-cache 需要进行协商缓存,发送请求到服务器确认是否使用缓存。或者可以使用 max-age=0
  • no-store 完全禁用缓存。
  • must-revalidateno-cache 类似,强制到服务端验证,适用于一些特殊场景,例如发送了校验请求,但发送失败了之类。
  • proxy-revalidate 与上面类似,要求代理缓存服务验证有效性。

添加成功后,刷新浏览器效果如下:

到此为止,我已经成功地解决了我的项目中的浏览器缓存优化问题。

需要注意的是,配置完成后,页面第一次刷新后还是旧代码,这是正常情况(因为浏览器仍在使用之前的缓存),清除缓存然后重新刷新即可。

我按照上面配置,多次测试发现可行,目前为止没有发现问题。如果大家觉得还不稳妥,还可以通过添加 ExpiresCache-Control 等响应头,控制浏览器缓存。配置完成后的效果如下:

压缩资源文件

另外,使用gzip压缩功能可以将网站的资源进行压缩,从而减少文件的大小,加快文件的下载速度,提高网站的访问速度。

切记,使用 gzip 压缩功能。不仅构建打包工具需要配置,nginx 也需要配置。 nginx 通过在 http 块中添加以下配置实现:

bash 复制代码
http {
    gzip on; # 开启gzip压缩
    gzip_min_length 1k; # 设置gzip压缩的最小文件大小
    gzip_buffers 16 8k; # 设置gzip压缩的缓存区大小
    gzip_http_version 1.0; # 设置gzip压缩使用的HTTP协议版本
    gzip_types text/plain text/css application/json application/javascript application/xml; # 设置需要gzip压缩的文件类型
}
  • 配置gzip压缩的文件类型,通过在gzip_types中添加需要进行gzip压缩的文件类型即可,例如上面的配置中,text/plain、text/css、application/json、application/javascript和application/xml这些文件类型会进行gzip压缩。
  • 配置gzip压缩的缓存区大小和最小文件大小,通过在gzip_buffers和gzip_min_length中设置缓存区大小和最小文件大小来控制gzip压缩的性能和效果。
  • 配置gzip压缩使用的HTTP协议版本,通过在gzip_http_version中设置gzip压缩使用的HTTP协议版本来控制gzip压缩的兼容性和稳定性。

配置成功如下:

其他常用缓存方案

使用DNS缓存和CDN缓存

除了浏览器缓存之外,DNS缓存和CDN缓存也是优化网站访问速度的重要手段。

DNS缓存可以加速域名解析,CDN缓存可以加速网站的内容分发。使用CDN可以将网站的静态资源文件缓存到CDN节点中,从而提高网站的访问速度。

在使用这些缓存技术的同时,还需要注意缓存的更新策略,避免出现过期缓存的情况。

我遇到过资源发布不更新问题,定位挺长时间,没有找到原因,最后找后端更新 CDN 才解决。

减少HTTP请求次数

减少HTTP请求次数可以减少网站的下载时间,从而提高网站的访问速度。可以通过合并文件、压缩文件等方式来减少HTTP请求次数。

减少重定向次数

重定向会增加网站的加载时间,从而降低网站的访问速度。可以通过合理的URL设计、避免链式重定向等方式来减少重定向次数。

除此之外还可以通过使用HTTP/2协议多路复用、二进制协议、头部压缩等功能、使用Memcached、Redis等缓存技术来优化网站的访问速度。

结语

总之,浏览器缓存优化可以大大提高网站的访问速度,减少服务器负载,提高用户体验。采取合适的缓存优化方案可以帮助我们更好地利用浏览器缓存,提高网站的性能和用户体验。

相关推荐
崔庆才丨静觅5 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅6 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅7 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊7 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax