如何配置Nginx请求路由解决多子应用静态资源加载异常问题
管理后台基于React构建,默认打包生成的入口HTML中,静态资源(JS、CSS、字体、图片等)的引用路径默认指向站点根路径/。当通过/admin前缀访问管理后台时,浏览器解析资源路径会请求/assets/xxx地址,该地址不符合/api、/admin的前缀匹配规则,会被网关直接转发到前端应用服务,前端应用的静态资源目录下不存在管理后台的对应资源,就会返回404导致页面渲染异常。
按优先级从核心到兜底依次调整,即可解决问题:
修正管理后台React项目的打包公共路径配置
这是解决问题的核心,需要让打包产物的资源引用路径自动携带/admin前缀,不同构建工具的配置方式如下:- 若使用Create React App构建且未eject:在项目根目录新建或修改
.env.production文件,添加配置PUBLIC_URL=/admin,重新打包后资源引用会自动变为/admin/assets/xxx格式 - 若使用自定义Webpack构建:修改webpack配置中
output.publicPath字段值为/admin/,注意末尾保留斜杠 - 若使用Vite构建:修改
vite.config.js/ts中的base配置项值为/admin/
额外注意:管理后台如果使用React Router,需要给路由组件设置basename属性为/admin,可以直接读取构建工具注入的环境变量(CRA场景用process.env.PUBLIC_URL、Vite场景用import.meta.env.BASE_URL),和打包公共路径保持一致,避免前端路由跳转到根路径下的前端应用。
- 若使用Create React App构建且未eject:在项目根目录新建或修改
调整网关/Ingress路由匹配规则,避免路径误截
路由匹配优先级保持/api>/admin> 其余路径转前端应用的规则,同时优化前缀匹配逻辑,避免/admin/assets这类静态资源路径被通配规则转发到前端服务。以K8s Ingress为例,参考配置如下:paths: - path: /api(/|$)(.*) pathType: Prefix backend: service: name: backend-java-service port: number: 8080 - path: /admin(/|$)(.*) pathType: Prefix backend: service: name: admin-react-service port: number: 80 - path: /(.*) pathType: Prefix backend: service: name: frontend-react-service port: number: 80配置中
(/|$)(.*)的正则可以避免/adminxxx这类非法路径被误转发到管理后台服务,同时保证/admin、/admin/、/admin/assets/xxx等所有带/admin前缀的合法路径都能正确到达管理后台服务。配置管理后台服务端的路由兜底规则
管理后台作为单页应用,需要服务端将非静态资源的子路由请求兜底返回index.html,否则刷新内页会出现404。如果管理后台使用Nginx托管Docker容器内的静态构建产物,参考配置如下:location /admin { alias /usr/share/nginx/html; try_files $uri $uri/ /admin/index.html; # 静态资源设置长期缓存 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ { expires 30d; add_header Cache-Control "public, immutable"; } }注意这里用
alias而非root做路径映射:如果用root,请求/admin/assets/a.js会映射到容器内/usr/share/nginx/html/admin/assets/a.js路径,和打包产物的目录结构不匹配会报404;用alias会直接映射到/usr/share/nginx/html/assets/a.js,和打包结构完全一致。
- 重新构建管理后台镜像并部署后,访问
/admin打开浏览器开发者工具,查看网络面板确认所有静态资源请求路径均为/admin/assets/xxx格式,返回状态码为200 - 点击管理后台内的菜单跳转路由、刷新内页,确认不会跳转到前端应用页面,无资源加载报错
- 验证普通前端页面访问、
/api前缀下的接口请求均正常,不受配置调整影响
内容的提问来源于stack exchange,提问作者tydiku

