闻心阁

一蓑烟雨看苍生,半壶浊酒笑红尘

前端SPA应用发版后用户白屏的解决方案

2022-05-16 约 1 分钟读完 搬砖秘籍

接手了一个前端老项目,使用React开发的SPA,最近几次短周期发版之后,收到了用户大量的体验反馈,其中比较多的就是白屏。

问题回放

问题出现集中出现在发版之后的短时间内,从用户反馈来看,页面大约长这样:

在这个页面里无论等待多久就是加载不出来。

问题原因

找这个问题还是花了一点时间来复现,后面专门找了一次发版的契机,才把这个问题抓到。查看控制台,大约报错如下:

xxxxxx.js 404

问题比较明显,就是这个页面的js从服务器取不到了。为什么会有这个问题?这与我们发版机制有关,目前的前端发版是直接把前端工程打包成一个dist文件夹,然后把它打到docker的镜像里,最后直接将这个docker镜像部署。

有没有什么问题?这种部署方式直接替换掉原来的镜像,而现代化的前端工程打包出来的js文件名一般会带一个hash值,所以导致如果用户缓存了老版本的js文件请求的话,直接替换就会出现这种404的白屏问题。

可为什么会缓存js文件?我们再看看我们的Dockfile,如下:

FROM xxxxx.xxxxx.xxx/nginx:latest

ADD  ./dist /usr/share/nginx/html

注意:数据脱敏隐藏了内部的docker地址。

但我们可以发现这里使用的比较粗暴,直接用的Nginx的默认配置,我们在本地启动一个Nginx的docker测试一下,发现默认情况下,Nginx会缓存html文件

解决方案

明白了问题,解决方案也比较简单了,有两种可行方案。

  1. 让用户刷新一下(不要笑,B端的系统有的真就是可以这样,但我觉得不好)
  2. 改一下Nginx,默认不缓存HTML文件

我采用的方案二,添加了一个自定义的nginx.conf配置文件,替换掉原来的默认配置,这样就不会缓存html文件了。

nginx.conf 文件内容如下

server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;

        if ($request_filename ~* ^.*?.(html|htm)$) {
            add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
        }
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

}

再修改下Dockfile, 用这个新的配置替换掉默认配置。

FROM xxxx.xxxxxxxx/nginx:latest 

#上面修改成你的docker镜像地址

ADD  ./dist /usr/share/nginx/html
ADD ./conf/nginx.conf /etc/nginx/conf.d/default.conf

真的解决了吗?

考虑一种极端情况,如果用户一直开着页面不关呢?这个时候,当前的解决方案就无法满足要求了。

那这种情况有没有方案呢?

我能想到的几种方法:

  1. 前端工程部署到CDN
  2. 定时刷新(比如1个小时)
  3. 打包的时候可以集成上一个版本

更多的方案暂时也没想到,有更好解决方案的小伙伴欢迎交流。