前端项目 OSS 访问部署踩坑记录

事件背景

部门内同时有多项业务的存在，为了便于访问和管理，整个系统采用乾坤架构，每个业务开发自己的子应用，然后统一挂载到基座应用使用。其大致结构如下：

Copy
➜ Project tree
.
├── ASCM
│   └── index.html
├── OSCM
│   └── index.html
├── PSCM
│   └── index.html
├── TMS
│   └── index.html
├── VSCM
│   └── index.html
├── assets
│   ├── dist.css
│   └── dist.js
└── index.html

7 directories, 8 files

在过去相当长的一段时间里，我们的全部应用都是在编译机器上编译打包后上传，然后 Nginx 中直接指定静态文件目录来访问。配置如下：

Copy
server {
listen 80;
server_name xxx.test.demo.local;

client_max_body_size 15M;
access_log logs/halley.access.log log_access; # 日志输出目录
gzip on;
gzip_min_length 1k;

location ^~ / {
root /mnt/work/h5/project-dist/;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}

本来这是很普通常用的方案。但是由于内部运维平台自身的一些问题，在把新的主应用部署到生产环境的时候（测试和预发没有问题），会直接清空掉整个 Project 文件夹的内容再释放新资源，而不是单纯的覆盖。这就意味着每次更新都会清空掉内部的子应用，使得基座发版 === 重新发布全部应用

虽然发版频率并不高（一个月两次左右），但是随着子应用的数目增加，这依旧成了一项很重的负担。更不论某些和工厂相关的应用白天不能中断，只能放到半夜一起更新，遂萌生了彻底解决问题的念头。

然而，在和运维沟通后，得知现在使用的运维平台几乎无人维护，有需求要自行迁移到另一套系统。

迁移过程

发布原理

在中台上使用容器作为构建环境，读取仓库内用户自行编写的 build.sh 进行构建，构建后将 dist 目录下的产物推送到 oss/s3 上，然后通过内部路由将 url 解析到 index.html 的 oss/s3 地址上。

项目更新

编写脚本

在项目下新增 build.sh，内容为

Copy
#! /bin/sh
. ~/.profile
yarn install --registry http://npm.xxxx.local:7001 --ignore-engines
export CICD_STATIC_PATH=$(echo $CICD_STATIC_PATH) && yarn build

构建系统会把本次构建内容的 oss 地址存储为 CICD_STATIC_PATH 变量，在脚本中自行获取后传递给 webpack 用以构建资源。

更新 Webpack

修正 webpack.config.js 中相关资源路径

Copy
const publicPath = {
dev: `http://${process.env.HOST}:${process.env.PORT}/`,
production: process.env.CICD_STATIC_PATH
};

Copy
{
path: __dirname + '/dist/', // 将打包好的文件放在此路径下，dev 模式中，只会在内存中存在，不会真正的打包到此路径
publicPath: publicPath[process.env.NODE_ENV], // 文件解析路径，index.html 中引用的路径会被设置为相对于此路径
filename: process.env.NODE_ENV === 'dev' ? 'bundle.js' : 'bundle-[contenthash].js' // 编译后的文件名字
}

更新 Nginx 配置

Copy
server {
listen 80;
server_name xxx.test.demo.local;

client_max_body_size 15M;
access_log /var/log/nginx/halley.access.log ; # 日志输出目录
gzip on;
gzip_min_length 1k;

location ^~ / {
proxy_set_header X-Scheme $scheme; # 传递协议
proxy_set_header Host apisix-area.test.demo.com; # 传递域名
proxy_set_header X-Real-IP $remote_addr; # 传递 ip
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

add_header X-Rewrite-Result $uri;
proxy_intercept_errors on;
error_page 400 403 404 500 = 200 /index.html;
proxy_pass http://apisix-area.test.demo.com/xxx/xxx-project/;
}
}

其中 http://apisix-area.test.demo.com 由运维统一提供，静态资源路径在构建时由 shell 脚本从 CICD_STATIC_PATH 变量读取。

更新后不再使用静态资源，而是完全通过 proxy_pass 代理到远程 oss 上的资源进行访问。由于项目是 React 构建，拥有自己的前端路由，并且 js/css 等静态资源会被自动上传到 CICD_STATIC_PATH 这个域名下，所以此处只需要把访问失败的请求全都代理到 oss 上的 index.html 即可。

题外话

配置 Nginx 的时候自行在本地用 docker 起一个服务来做测试会方便一点，免得更新服务端配置又要没完地扯皮。感觉其中很多时间都浪费在了找人和走流程上面，蛮不愉快的。