web缓存问题的解决方案

背景

单页面应用

现代前端框架大多数走的是单页面应用路线,vue项目即是。对于这类应用,浏览器加载的内容主要为:

  1. 入口html文件:index.html
  2. 资源文件:chunk-vendors.*

浏览器缓存机制

浏览器缓存机制会使浏览器缓存许多类型的HTTP请求,包括.html.js.css

浏览器缓存机制的目的在于减少网络请求,提高网页加载速度,优化用户体验。也许有些时候它很讨厌:

有新更新的时候

但有的时候它很可爱:

当用户加载页面需要长达5s甚至更长的时间时

相比起可爱之处,它的讨厌之处是可以通过一些方法化解的。这就是接下来的内容。

缓存问题的解决之道

综上所述,要解决缓存带来的困扰,我们需要:

  1. 使得客户端及时更新index.html,只有这样才能够有机会更新.js.css文件。以下是一个模拟的index.html资源,用于理解为什么"只有这样"

    xml 复制代码
    <html>
        <head>
        /*省略其他项*/
        <link href="xx/xx/chunk-vendors.css"></link>
      </head>
        <body>
        <script type="text/javascript" src="xx/xx/chunk-vendors.js"></script>
        </body>
    </html>

    单页面应用中的资源文件.js.css是要通过index.html加载的。但是在完成版本更新之后,我们大多数时候已经移除了上一版本的js包,可是客户端仍能顺利完成加载,这是因为,连资源文件也一并缓存了。

  2. 更新资源文件,这里应该被分为两个部分:客户端请求新的资源文件(依赖index.html的更新),服务端提供新的资源文件。这里可以通过添加hash命名的方式使得新的index.html中使用新的资源包名,打包出来的资源文件也是对应的新包名

    xml 复制代码
    <html>
        <head>
        /*省略其他项*/
        <link href="xx/xx/chunk-vendors.78ushgag7y.css"></link>
      </head>
        <body>
        <script type="text/javascript" src="xx/xx/chunk-vendors.fgwjkrhakg23.js"></script>
        </body>
    </html>

    中间的乱码是模拟的hash值

1.入口文件index.html

这里采用协商缓存机制解决index.html的缓存

step-1.服务端添加响应头

arduino 复制代码
Cache-Control: 'private no-cache'

其中:

  • private: 仅允许响应被发送请求的客户端缓存(排除可能的中间代理的缓存)
  • no-cache: 客户端缓存内容,但是否使用缓存需要经过协商缓存决定

这个需要在nginx等服务器上匹配index.html的请求路径,添加响应头实现

这里需要说明,仅仅在页面上添加<meta http-equiv="Cache-Control" content="no-cache" />是不够的,因为浏览器在处理缓存时,依赖于 HTTP 响应头中的 Cache-Control,所以这部分应该由服务端进行设置

step-2.协商缓存

1-首次请求资源时,服务器会在响应头中包含ETagLast-Modified

Nginx默认会为静态文件生成ETag

其他服务器应该也有类似实现

2-客户端再次请求时,在请求头中加入If-None-MatchorIf-Modified-since

If-None-Match: 上次响应头中的Etag

If-Modified-since: 上次响应头中的Last-Modified

3-服务器验证

有两对头信息可以用于协商缓存。

If-None-Match&ETag

If-Modified-since&Last-Modified

服务器比较请求头If-None-Match与当前的ETagIf-Modified-since与当前的Last-Modified是否匹配。

  • 匹配:触发304 Not Modified响应告诉浏览器使用缓存的版本
  • 不匹配:返回新的响应(新的静态页面、ETagLast-Modified)

2.资源文件

应用打包时配置hash打包即可,这样打包之后的资源文件就会带上hash值避免重复。

由于不同的打包工具、不同的插件应用有不同的写法,这一步可以自由尝试。

总结

通过以上方式,可以有效解决浏览器缓存问题,包括微信小程序的webview缓存。目前已测试较新的IOS机器和Android机器。

同时注意到:

协商缓存机制主要依赖于HTTP协议而不是浏览器特性,以上提到的HTTP头在HTTP/1.1规范中定义,这就意味着只要浏览器支持HTTP/1.1或更高版本协议,就可以支持协商缓存机制。

具体的行为也会受到浏览器设置、用户行为、网络条件的影响,因此更重要的是参考实际情况。比如在浏览器中用户手动进行了缓存设置的情况。

相关推荐
前端大卫3 小时前
Vue3 + Element-Plus 自定义虚拟表格滚动实现方案【附源码】
前端
却尘3 小时前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare3 小时前
浅浅看一下设计模式
前端
Lee川3 小时前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试
Ticnix3 小时前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人3 小时前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl3 小时前
OpenClaw 深度技术解析
前端
崔庆才丨静觅3 小时前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人4 小时前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼4 小时前
shadcn/ui,给你一个真正可控的UI组件库
前端