{
"title": "前端项目 OSS 访问部署踩坑记录",
"tags": [
"post",
"踩坑",
"记录"
],
"summary": "通过 Nginx 的 porxy_pass 来代理存储在 oss/s3 上的 React 项目访问",
"sources": [
"xlog"
],
"external_urls": [
"https://zsakvo.xlog.app/react-project-on-oss"
],
"date_published": "2023-04-07T02:44:43.580Z",
"content": "## 事件背景\n\n部门内同时有多项业务的存在,为了便于访问和管理,整个系统采用乾坤架构,每个业务开发自己的子应用,然后统一挂载到基座应用使用。其大致结构如下:\n\n```shell\n➜ Project tree\n.\n├── ASCM\n│ └── index.html\n├── OSCM\n│ └── index.html\n├── PSCM\n│ └── index.html\n├── TMS\n│ └── index.html\n├── VSCM\n│ └── index.html\n├── assets\n│ ├── dist.css\n│ └── dist.js\n└── index.html\n\n7 directories, 8 files\n```\n\n\n在过去相当长的一段时间里,我们的全部应用都是在编译机器上编译打包后上传,然后 Nginx 中直接指定静态文件目录来访问。配置如下:\n\n```conf\nserver {\n listen 80;\n server_name xxx.test.demo.local;\n\n client_max_body_size 15M;\n access_log logs/halley.access.log log_access; # 日志输出目录\n gzip on;\n gzip_min_length 1k;\n\n location ^~ / {\n root /mnt/work/h5/project-dist/;\n index index.html index.htm;\n try_files $uri $uri/ /index.html;\n }\n}\n```\n\n本来这是很普通常用的方案。但是由于内部运维平台自身的一些问题,在把新的主应用部署到生产环境的时候(测试和预发没有问题),会直接清空掉整个 Project 文件夹的内容再释放新资源,而不是单纯的覆盖。这就意味着每次更新都会清空掉内部的子应用,使得`基座发版 === 重新发布全部应用`\n\n虽然发版频率并不高(一个月两次左右),但是随着子应用的数目增加,这依旧成了一项很重的负担。更不论某些和工厂相关的应用白天不能中断,只能放到半夜一起更新,遂萌生了彻底解决问题的念头。\n\n然而,在和运维沟通后,得知现在使用的运维平台几乎无人维护,有需求要自行迁移到另一套系统。\n\n\n## 迁移过程\n\n### 发布原理\n在中台上使用容器作为构建环境,读取仓库内用户自行编写的 build.sh 进行构建,构建后将 dist 目录下的产物推送到 oss/s3 上,然后通过内部路由将 url 解析到 index.html 的 oss/s3 地址上。\n\n### 项目更新\n\n#### 编写脚本\n在项目下新增 build.sh,内容为\n```shell\n#! /bin/sh\n. ~/.profile\nyarn install --registry http://npm.xxxx.local:7001 --ignore-engines\nexport CICD_STATIC_PATH=$(echo $CICD_STATIC_PATH) && yarn build\n```\n\n构建系统会把本次构建内容的 oss 地址存储为 `CICD_STATIC_PATH` 变量,在脚本中自行获取后传递给 webpack 用以构建资源。\n\n#### 更新 Webpack\n修正 webpack.config.js 中相关资源路径\n```javascript\nconst publicPath = {\n dev: `http://${process.env.HOST}:${process.env.PORT}/`,\n production: process.env.CICD_STATIC_PATH\n};\n```\n\n```json\n{\n path: __dirname + '/dist/', // 将打包好的文件放在此路径下,dev 模式中,只会在内存中存在,不会真正的打包到此路径\n publicPath: publicPath[process.env.NODE_ENV], // 文件解析路径,index.html 中引用的路径会被设置为相对于此路径\n filename: process.env.NODE_ENV === 'dev' ? 'bundle.js' : 'bundle-[contenthash].js' // 编译后的文件名字\n}\n```\n\n#### 更新 Nginx 配置\n```conf\nserver {\n listen 80;\n server_name xxx.test.demo.local;\n\n client_max_body_size 15M;\n access_log /var/log/nginx/halley.access.log ; # 日志输出目录\n gzip on;\n gzip_min_length 1k;\n\n location ^~ / {\n proxy_set_header X-Scheme $scheme; # 传递协议\n proxy_set_header Host apisix-area.test.demo.com; # 传递域名\n proxy_set_header X-Real-IP $remote_addr; # 传递 ip\n proxy_set_header REMOTE-HOST $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n\n add_header X-Rewrite-Result $uri;\n proxy_intercept_errors on;\n error_page 400 403 404 500 = 200 /index.html;\n proxy_pass http://apisix-area.test.demo.com/xxx/xxx-project/;\n }\n}\n```\n其中 `http://apisix-area.test.demo.com` 由运维统一提供,静态资源路径在构建时由 shell 脚本从 `CICD_STATIC_PATH` 变量读取。\n\n更新后不再使用静态资源,而是完全通过 proxy_pass 代理到远程 oss 上的资源进行访问。由于项目是 React 构建,拥有自己的前端路由,并且 js/css 等静态资源会被自动上传到 `CICD_STATIC_PATH` 这个域名下,所以此处只需要把访问失败的请求全都代理到 oss 上的 index.html 即可。\n\n## 题外话\n配置 Nginx 的时候自行在本地用 docker 起一个服务来做测试会方便一点,免得更新服务端配置又要没完地扯皮。感觉其中很多时间都浪费在了找人和走流程上面,蛮不愉快的。\n\n",
"attributes": [
{
"value": "react-project-on-oss",
"trait_type": "xlog_slug"
}
]
}