如何在AWS负载均衡器后更新React应用避免main.js哈希变更致404
AWS CodeDeploy部署React应用的资源加载404问题解决
问题背景
我正在使用AWS CodeDeploy部署React应用,应用由npx create-react-app执行npm build构建生成,目录结构如下:
/var/www/my-website . ├── asset-manifest.json ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json ├── robots.txt └── static ├── css │ ├── main.2be1a5a0.css │ └── main.2be1a5a0.css.map ├── js │ ├── 787.28cb0dcd.chunk.js │ ├── 787.28cb0dcd.chunk.js.map │ ├── main.77918f81.js │ ├── main.77918f81.js.LICENSE.txt │ └── main.77918f81.js.map └── media ├── ...
生成的index.html核心内容:
<!doctype html> <html lang="en"> <head> <!-- 省略meta等基础配置 --> <title>React App</title> <script defer="defer" src="/static/js/main.77918f81.js"></script> <link href="/static/css/main.2be1a5a0.css" rel="stylesheet"> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> </body> </html>
EC2实例的Nginx配置:
server { listen 80; listen [::]:80; server_name _; root /var/www/my-website; include /etc/nginx/default.d/*.conf; error_page 404 /404.html; location = /404.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } }
部署时的资源加载问题
当在AWS负载均衡器后使用in-place或blue/green部署方式时,新旧实例会共存一段时间(直到in-place部署完成或blue/green注销所有旧实例),此时会出现以下问题:
- 请求路由到旧实例,返回包含旧哈希资源路径(如
/static/js/main.hash1.js)的index.html - 浏览器通过负载均衡器发起资源请求,被分发到新实例
- 新实例不存在该旧哈希资源,返回404错误
反向场景(先拿到新版本index.html,再请求旧资源)也会触发同样问题,只有所有请求命中同一版本实例时才能正常运行。
解决方案
1. 构建时使用相对路径,避免跨实例请求
修改项目根目录的package.json,添加homepage字段为./:
{ "name": "my-react-app", "homepage": "./", // 其他项目配置字段... }
重新执行npm run build,构建后的index.html中资源路径会变为相对路径:
<script defer="defer" src="./static/js/main.77918f81.js"></script> <link href="./static/css/main.2be1a5a0.css" rel="stylesheet">
这样浏览器会从当前请求的实例加载资源,不会通过负载均衡器跨实例请求不同版本的资源。
2. 多版本资源保留+Nginx动态指向
- 修改CodeDeploy部署脚本,将新版本部署到带版本标识的子目录,比如
/var/www/my-website/v202405201200 - 更新Nginx配置,将
root指向最新版本的子目录,同时保留旧版本目录一段时间 - 示例Nginx配置修改:
server { listen 80; listen [::]:80; server_name _; # 指向最新版本目录 root /var/www/my-website/v202405201200; include /etc/nginx/default.d/*.conf; # 可选:如果请求的资源在当前版本不存在,尝试从旧版本加载 location ~* ^/static/ { try_files $uri /../v202405191000$uri =404; } error_page 404 /404.html; location = /404.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } }
- 后续可通过定时任务清理超过7天的旧版本目录,避免磁盘占用过高。
3. 优化Blue/Green部署流程
- 使用Blue/Green部署时,不要急于销毁蓝色(旧)环境实例,等待至少1-2个小时(根据用户会话时长调整)后再清理旧实例
- 确保所有已加载旧版本index.html的用户都完成资源请求后,再删除旧环境的资源
4. 配置负载均衡器的会话粘性
- 给负载均衡器开启会话粘性(粘性会话),让同一个用户的请求始终路由到同一个实例
- 这样用户一旦加载了某个版本的index.html,后续资源请求都会命中同一个实例,避免跨版本资源请求问题
- 注意:该方案仅适用于用户会话较短的场景,长期会话可能会导致用户无法及时获取新版本。
内容的提问来源于stack exchange,提问作者peterulb
相关产品推荐
相关产品推荐

