微信浏览器内单页应用缓存问题解决方案实践

发布于:2021-11-29 11:04:47

一、问题背景

问题描述:


微信内单页web应用,在进行版本迭代的时候,尝尝会遇到一个老大难问题。----缓存


大部分用户,通过链接进入我们的应用,一般都不会去手动刷新一下我们的应用(右上角三个点,然后点击刷新),


这样就会导致我们对程序版本迭代和内容更新的时候,总有一些手机用户因为缓存原因,内容无法及时的更新或者产生错误的展示。


系统环境:


前端单页页面(vue页面通过vue-cli打包生成的单页)+ Nginx反向代理服务(充当静态资源服务器)?+ 微信浏览器


二、问题分析

首先得吐槽一下微信端的浏览器内核,简单的用一个段子来形容它:微信浏览器就是IE和阳光沙滩(sun of beach)的私生子。


我们通常用来处理浏览器缓存的解决方案,基本上在微信浏览器中都不出意外的没有任何效果。更甚者不同的手机也用户,缓存的严重程度也不太一样。


要处理解决缓存问题,首先我们需要工具来验证,我们的去除缓存的解决方案是否有效。我这里能想到的最直观的方式就是通过对手机抓包,将手机从微信浏览器发起请求后的完整链路有个直观的展示。这里我推荐windows用户,可以使用Fiddler。后文也将结合该工具为大家证明解决方案的有效性。


其次,我们对缓存进行分类,这里将缓存分成两大类:静态资源、网络请求。本文讨论的是前者。


三、实践过程

刚刚说了,常规的解决缓存的方案,都没有效果。最简单就是添加meta(无效):



接下来我们就先来分析下我们的应用组成。由于我们的应用是单页程序,所有整个程序只要一个html文件,这里就叫做index.html,在index.html中我们会加载对应的静态资源。这也就是说,静态资源的缓存就是指index.html文件和其内部引用的资源文件。那么是index.html文件被微信浏览器缓存了,导致我们最新的程序功能没有被及时的更新,还是index.html的内部引用的资源文件被缓存了呢?如果你的项目使用了打包工具,并且对资源文件的命名使用了混淆比如md5(vue-cli打包出的 静态文件名称都会被加上MD5串)。其中生成的原理大致就是根据你这个资源文件,生成的md5串,这个MD5串作为你文件名称的一部分。也就是说,资源文件的内容改变,对应的文件的md5必定也会改变,所以生成出来的文件名称,也肯定会改变。如图:



那么很明显,因为内部引用的资源文件的缓存可能性很小,问题就在与我们的入口index.html文件。


资源请求场景-复盘


1.用户通过微信端,第一次进入我们的单页应用,浏览器正常向我们的nginx服务获取资源。如图:



通过抓包工具,我们拦截到手机正常向我们的服务请求资源。可以看到请求的状态是result:200,body:1378 (正常请求)


2.那么我们再一次向服务请求相同地址时候,同样进行抓包,如图:



再第二次进行请求的时候,我们发现请求的状态是result:304,body:0(不重新获取资源)


要详细的了解还请自行查阅资料。这里简单说下状态码,304就表示:nginx告诉微信浏览器,我nginx上的index.html没有变化,你微信可以从你原来的缓存里面去找index.html的内容。然后微信就用了上一次请求的资源,不重新获取新的资源了。


既然微信不再获取新的资源了,所以你的新版本的代码也就是在index.html文件的资源文件也就引用的路径还是原来的路径,如果你原来的index内部引用资源文件被删除了,那么会有两种结果:1.这个时候请求可能会报错,因为资源文件找不到;2.浏览器之前缓存了这个文件,那么你的代码可以正常执行,只不过执行的是你原来的*姹镜拇搿


注意:注意:注意:


这里的304只是一个比方,具体微信再走缓存的场景也可能是其他的状态码或者其他情况,因为博主一直多次进行版本迭代,反复尝试,没有出现缓存的问题,所有这里就拿304状态简单打了个比方。(后面有人能重新缓存问题,还请告知实际的情况)。


解释下304状态码 :表示nginx上的index.html文件内容没有改变,正常情况下,如果index.html文件被改变以后,nginx返回的状态码会变成200所以,微信端还是会发起新的请求获取新的index.html。所以因为文件没有改变得到状态码304是正常的。


明确目的


接下来我们的目标就明确了,


做到让微信不从自己的缓存里面去找index.html,或者说让nginx,每次微信过来,都告诉微信,现在的index是最新的,微信要重新获取。


假设我们通过访问一个域名http://www.XXX.com(虚构的),该域名在就是访问nginx配置的index.html。我们现在希望的效果是第一次访问,微信会去获取index.html的真实信息,第二次的时候,仍然是去获取nginx的真实信息。


通过查阅相关资料后,最后我们发现我们只需要为我们的nginx的配置下静态文件index.html的缓存机制就行了。将html等文件类型的缓存类型设置成为不缓存。如果是其他服务器,应该也是大同小异,修改各自服务器静态资源的缓存策略。


nginx为例就是设置


1. expires: -1;


2. add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";


location ~ .*.(?:htm|html)$ {
expires -1;
add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
}


在查阅资料中,最初发现可以通过只设置expires,结果在我的项目中不管用,后来就又加上了add_header Cache-Control这才解决。


我们通过抓包来验证一下,现在多次访问我们的单页应用,会不会进行强制不缓存



在这里我们发现,我们两次通过公众号的地址进入到我们的单页应用时,每次都会重新触发请求,现在就再也不怕缓存了,因此我们每次进来,微信都不会对我们的首屏页面去做缓存了。在这里我们需要注意的是,我们刚刚的配置,只是对html强制不缓存,但是对于我们index.html内的资源,我们没有去做处理,原因就是前面说的,index内的引用资源如果改变,都会生成新的文件名称,因此我们不需要担心它的缓存问题。我们只要保证index.html的内容是最新的就OK了。


这里补充两点,1.细心的朋友可以看到我的配置里面加入了root参数,因为我们项目在nginx下设置了多套环境,每套项目的在不同的文件夹下,你如果只有一个环境,而且静态资源是放在html文件夹下的,这里可以忽略不写。博主对nginx也不太懂,有些配置也不太清楚。2.可能有些朋友没有使用打包工具,解决了index.html缓存问题,还有内部资源文件缓存的问题,这个问题你也可以通过nginx配置完成强制nginx不缓存js、image、css等等静态资源。但是我没有尝试过这能不能达到让微信浏览器不对这些文件进行缓存,也就是说,配置nginx能做的就是让nginx告诉微信浏览器不要去缓存,微信浏览器到底听不听,我没有去验证过。但是,建议还是通过打包工具动态生成的好,少操心。


四、问题总结

抓包、抓包、抓包,重要的事情说三遍,有事没事抓个包,将网络数据的整个流程尽收眼底,会让问题真实的暴露在你的眼前。可能有些同学觉得博主写的过于繁琐,不如直接说自己的解决方案。其实博主是觉得,也许我的解决方案可能更多的是适合于我项目的应用场景,我也更希望通过把我对这个问题的解决的过程描述清楚,也许解决过程中的某一个点,能给后面踩坑的同学一些小小的借鉴,那样也是极好的。


?


感谢以下同学的分享


参考资料:


https://www.jianshu.com/p/cce9511c0914


https://blog.csdn.net/php12345679/article/details/80844759


https://blog.csdn.net/jiabeis/article/details/79653983


https://segmentfault.com/a/1190000007317481

相关推荐

最新更新

猜你喜欢