发布网友 发布时间:2024-09-05 03:01
共1个回答
热心网友 时间:2024-09-05 13:02
背景微信小程序中的web-view嵌入了h5的页面,h5页面更新重新发版后,web-view访问还是之前的页面。
在本地调试,我们可以通过开发者工具的清除缓存功能,如果是手机访问可以通过删除小程序,再重新进入,以达到清除缓存的效果。但是不可能让我们的用户都这么操作,所以我们接下来要分析出现这种情况的原因及对应的解决方案。
如果想直接看解决方案的可以拉到最下面
原因分析这种页面已经更新,但是访问时还是旧版的情况,我们可以轻易的联想到就是页面缓存的影响:在首次访问页面时,客户端将页面内容缓存起来了,导致下次访问时直接使用的本地缓存中的内容。而我们单页应用缓存的考虑一般是2个方面。
入口html文件缓存
页面引入的静态资源缓存
入口html文件缓存这种缓存,就是我们html本身的内容被缓存了,包括引入的静态资源路径等。因为在单页应用中,我们所有的内容都是通过入口html引入的js文件来加载的。所以如果html被缓存,那我们就算更改了页面内容,再次访问也还是之前的。接下来让我们来验证我们的猜想。
验证1、首先通过web-view访问我们的h5页面,通过web-view的调试工具,查看入口html文件的内容,如下:
2、修改入口html文件内容
如:在html的head中新增一个meta标签
<metaname="description"content="测试缓存"/>3、将h5重新发布
此时,再通过小程序web-view访问该页面,同样通过调试工具查看页面代码。发现head中没有我们新添加的meta标签。
通过web-view的调试工具,我们同样可以发现,第二次页面的访问是直接走的本地缓存。
此时,我们可以得出结论:入口html文件被缓存了。所以,不管我们怎么更改页面内容,后续小程序访问到的还是之前缓存的那一版内容。那如果我们修改了h5内部的组件代码呢?
进一步验证1、修改任意组件中的内容(会导致js或css文件的变更即可),并将h5重新发布2、在chrome浏览器中访问(确保我们访问的是最新的代码),查看html文件引入的内容;或直接查看新的打包文件。对比上一次版本。
可以发现我们引入的的app.js文件名变更了
app.js文件名由原来的app.6dca15e7.js变更为了app.a68f992c.js
3、小程序的webview中访问该h5页面,发现小程序中html页面引入的app.js文件地址还是原来的app.6dca15e7.js,这也就进一步验证了我们上面说的html文件被缓存了。
页面引入的静态资源被缓存此时,思考一个问题:因为我们的静态资源发布在服务器上是覆盖式发布,新发布h5页面后,就会使用整个新的包替换掉原来的老包,app.6dca15e7.js这个文件是上一版中的静态资源,在我们新发布h5之后,该文件在服务器上面就已经不存在了,那为什么小程序这里还是能正常访问到?
我们可以测试下,直接在浏览器中分别访问新旧app.js的资源,看看能否访问到。
新:app.a68f992c.js(可以正常访问到)
旧:app.6dca15e7.js(无法访问到)
上面的测试说明,老文件已经被移除了。但是小程序中引入老文件为什么还是可以正常引入。这就是我们上面说的第二种缓存,页面引入的静态资源被缓存
我们还是通过web-view的调试工具来看看,发现小程序中引入的静态资源也是直接使用的本地缓存的。
解决方向根据上面的测试,我们可以发现,要想解决缓存问题,首先我们要解决入口html页面的缓存。否则不管我们内部的内容怎么变更,我们入口引入的js文件都不会变更,而我们的单页应用,又是基于入口引入的js文件进行渲染的,所以不管我们怎么更改内容,在小程序中看,页面都是之前的版本。其次就是解决静态资源被缓存的问题,上面可以看到页面引入的静态资源也会被缓存。
尝试几种不同解决方案入口html页面缓存1、设置meta标签(无效)我们先通过简单的方案,来看是否能够实现,首先想到的就是在html的head中设置meta标签。如下:
<metahttp-equiv="Cache-Control"content="no-cache,no-store,must-revalidate"><metahttp-equiv="Pragma"content="no-cache"><metahttp-equiv="Expires"content="0">告诉浏览器不要缓存当前页面,相当于http的请求头设置。看到有些文章说在chrome浏览器是能生效的,但是实测,不管是chrome浏览器中,还是微信中,都并没有生效,本来缓存的还是会走的缓存,并且在请求头中也没有添加相关的不缓存参数
2、给页面访问地址增加时间戳参数(无效)如,我们正常的页面方式地址(https://www.baidu.com),在该地址后添加t=1652666323379这种当前时间戳参数,确保每次访问的时候t参数的值都是不一样的。测试还是无效。
3、服务器配置页面不缓存(有效)在服务器中,给入口html页面的访问添加响应头,如在nginx中配置Cache-Control为no-store,no-cache。这样浏览器访问页面时,就不会缓存该页面。
如下,在服务器配置了该参数后,页面请求的响应头中有我们配置的不缓存参数,客户端就不会缓存该页面,后续的请求每次都是从服务器获取最新的页面文件。这里,我们入口html页面的缓存问题就被解决了
静态资源被缓存从上面的分析过程,我们可以看到,静态资源也会被客户端缓存。
比如app.js,如果我们未使用静态资源版本号,在我们修改内容重新发布前后,文件名始终都是app.js,此时就算我们请求了最新的html页面,但是html页面引入的js文件还是app.js,此时客户端会直接使用本地缓存的该文件,这样我们的内容还是未更新。
那针对这种缓存我们应该怎么解决?
1、静态资源增加版本号(建议)上面的分析过程中,我们已经使用了该方案,根据文件内容自动hash生成版本号,每次文件内容变更时,版本号也会自动变更。现有的大部分脚手架都有这种处理,如果没有的话,也可以自己配置下。
添加了版本号之后,app.js文件名,会使用app.hash.js这种格式,每次文件内容有变更就会生成一个新的文件。比如我们第一次访问页面,文件名为app.6dca15e7.js,再我们修改文件重新发布后,文件名变更为了app.a68f992c.js,我们入口文件引入的该文件名,也会变更为最新的文件名,这样就能够确保我们每次都是访问最新的静态资源。并且其他的静态资源没有改动,文件名也不会变更,还是可以继续使用本地缓存的文件。
这样我们既可以保证每次访问的资源都是最新的,又可以使用缓存来提升用户体验,缓解服务器压力。
静态资源版本号常见的2种方式:
文件访问带参数:index.js?v=db5854c9
文件名中带参数:index-db5854c9.js
注意需要第2种方式,因为对于第一种方式,部分浏览器可能会直接忽略后面的参数,不能确保一定能够生效。而第二种方式,相当于每次修改文件内容后,就会生成1个新的文件,就能确保每次使用都是最新的。
2、服务器配置静态资源不缓存不建议和页面缓存一样,在服务器中配置客户端不缓存静态资源。但是这样的话会导致每次请求页面,所有静态资源都会重新从服务器获取,这样对用户体验(打开页面的速度、宽带的占用)、服务器的压力都非常的不友好。所以不建议使用这种方式。直接使用版本号的方式即可。
最终解决方案:根据上面的分析,及多种解决方案的尝试,可以发现,解决这种缓存问题,需要我们做以下2个方面的处理:
在服务器中,给入口html页面添加不缓存的响应头,告知客户端不缓存html文件
静态资源添加版本号
其实不光是适用于微信小程序的web-view,微信浏览器内的缓存也可以通过同样的方式处理,之前在做微信公众号开发时,在微信浏览器中也遇到过相同的问题。包括其他的浏览器也适用,只是微信内的缓存尤为顽固,所以通常在微信内遇到的这种问题比较多
原文:https://juejin.cn/post/7098522027291574280