背景

最近接到需求,要求在原有同学的开发基础上,开发上线一系列新功能,其中用到的技术栈主要是 dva + umi.js + antd + roadhog。在开发完成项目之后,部署上线的流程遇到了许多坑,让人收益颇深。

问题一:

在上线之后,我推送代码到 gitlab, 然后在 rancher 上部署服务并修改版本号,这一切都没有报错,但是我们在域名下访问的时候却发现线上的功能并没有按照我们预期的要求更新功能,所以出现了线上还是出现老版本的情况。

问题二:

部署上线功能之后,我们在测试环境发现功能按照我们预期的要求完美执行,但是线上版本还是会出现问题,具体就是,用户在登陆的时候会访问当前域名下的后端接口,比如当前域名为:admin.baidu.com, 后端login的请求地址就会为:admin.baidu.com/login,而我们配置的环境变量却不是这个后端地址。

问题一的解决:

遇到问题一时,我们猜测会不会是缓存的原因,我们先在 chrome 的 dev tools 上开启了 disabled cache

然后发现并没有用。
继续猜测:会不会是当前域名下有缓存,然后我们联系了运维清除了当前域名下的缓存。
然后发现还是没用n
怎么回事,纠结了半天,还是n不到原因。
因为我们的服务使用了 nginx 服务,我们猜测会不会 nginx 有缓存,然后我们加上了 nginx header, 用来去除缓存:

1
2
3
4
5
6
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
add_header Cache-Control 'max-age=0, must-revalidate, no-cache';
}

因为线上服务不可能频繁测试,我们用 docker 在本地启动了一个 ngix 实例,结果发现 header 是有请求头的,符合我们的预期,但是上线之后才发现还是没有解决问题。

最后我们在远端的文件的时候发现了我们使用 umi build 进行打包的时候,打包文件没有加上 hash 值,也就是说打包上线的服务并没有唯一的文件,所以服务在启动的时候用的是以前的文件。
最后我们打上了 hash,解决了第一个问题;

问题二的解决:

有了第一个问题的经验,我们成功的去除了缓存的影响,但是发现为什么向后端请求的时候地址会是本域名呢,我们查看了 umi 的配置,发现他在 webpack 配置的时候是会去读取环境变量的值:

1
2
3
4
5
6
7
8
/**
* webpack 相关配置
*/
define: {
APP_TYPE: process.env.APP_TYPE || '',
API_HOST_ENV: process.env.API_HOST || '',
API_PORT_ENV: process.env.API_PORT || '',
},

而我们也配置了环境变量的值,但为什么环境变量的值不生效呢。

我们下载了线上的打包后的 umi.js 文件,在测试环境全局搜索当前文件下的后端ip地址,发现可以搜索到,但是线上正式环境却搜不到地址,这就说明线上的测试环境没有正确读到环境变量的值,而测试环境的流程和线上环境的流程几乎一模一样。

绞尽脑汁之后,我们在 gitlab 的 ci 脚本上找到了原因:

1
2
3
4
5
script:
- NODE_ENV=development npm install --registry=https://registry.npm.taobao.org
- npm run build:prd
- cp .env.example .env
- rm -fr node_modules

可以看到这个 script 先是执行了 NODE_ENV=development npm install, 再执行了 npm run build:prdcp .env.example .env 这两个命令,问题就出在这里,当我们在 build 之后再设置环境变量时,这样打包好的文件是不能成功读取到环境变量的值,只有在打包前设置环境变量,文件才能成功的读取到环境变量的值,并且设置到前端项目中。
而测试版本的脚本和线上发布的脚本只有这一行位置的差别。真是看瞎人的眼睛。

由此验证了一句不知道是谁说的话:
“一切解释不通的程序代码肯定都是低级错误”。