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或更高版本协议,就可以支持协商缓存机制。

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

相关推荐
KenXu几秒前
EMP微前端实现Vue2、Vue3、React各版本调用方案
前端
xw54 分钟前
一文搞懂Flex弹性布局空间分配规则
前端·css·flexbox
云枫晖13 分钟前
手写Promise-静态方法reoslve和reject
前端·javascript
浮幻云月17 分钟前
让 Vue 动画如德芙般丝滑!这个 FLIP 动画组件绝了!
前端·javascript
吃饺子不吃馅25 分钟前
揭秘 X6 核心概念:Graph、Node、Edge 与 View
前端·javascript·svg
qwy71522925816327 分钟前
Vue中的Provide/Inject如何实现动态数据
前端·javascript·vue.js
艾小码27 分钟前
告别重复代码!React自定义Hook让逻辑复用如此简单
前端·javascript·react.js
yoyoma29 分钟前
react-infinite-scroll-component 使用注意事项
前端
快乐是一切31 分钟前
PDF文件的交叉引用表(xref)与 trailer
前端
emma羊羊1 小时前
【CSRF】防御
前端·网络安全·csrf