RuoYi子路径部署实战:前端Nginx后端路径对齐与404排查
1. 子路径部署到底要解决什么问题1.1 为什么会有把 RuoYi 塞进子路径这种需求大部分时候我们在测试环境里部署 RuoYi 都很随意给个独立域名或者干脆用 IP 加端口前端跑在 80后端跑在 8080两边各管各的谁也不碍着谁。可一旦进了正式环境事情就变了。最常见的三种情况一是公司内网只开放了一个对外域名和一个 443 端口所有系统必须挂在同一个域名下面用/ruoyi/、/oa/、/report/这样的目录区分二是运维那边已经有一套统一门户反向代理层只能做目录级转发不给你分二级域名三是客户那边的网络策略卡得很死多开端口要写一堆审批不如全部收敛到一个入口。这三种场景的共同点就是你不能再假设前端一定在根路径/下运行。凡是代码里写死/prod-api、/static、/index.html的地方全部会出问题。而 RuoYi 这类脚手架为了开箱即用恰恰在不少地方默认就是根路径所以改部署路径这件事本质上不是改一个配置而是把前端、Nginx、后端三层的路径假设重新对齐一遍。我先说结论方便你判断这活儿值不值得自己干只要你理解了基础路径这个概念在三个层次上的传递关系整个改造大概半小时就能搞定但如果你只改了vite.config.js就以为完事了那接下来你会依次遇到白屏、静态资源 404、接口 404、刷新 404 这四个连环坑一个都跑不掉。1.2 子路径部署和独立域名部署差别到底在哪很多人觉得这两者差不多无非是路径长短不一样。实际差别挺大我列个表对比一下你就明白了。对比维度独立域名部署子路径部署前端资源引用/assets/xxx.js直接可用被解析成域名根目录必须改成/ruoyi/assets/...路由模式history 模式随便用history 模式需要 Nginx 兜底否则刷新 404Cookie 作用域默认整站默认整站多系统会互相覆盖需要限制 path接口前缀可以是/prod-api建议加前缀或靠 Nginx 重写剥离静态文件上传存/profile/upload直接访问需要额外 location 或加统一前缀调试难度低路径直观高一层套一层容易绕晕从表里能看出子路径部署额外的复杂度主要来自两个地方一是绝对路径的语义变了二是多系统共用一个域名带来的 Cookie 和路由冲突。前者靠改配置解决后者要靠合理的路径规划。我的习惯是给每个系统分配一个固定的短前缀比如 RuoYi 就用/ruoyi/前端页面走/ruoyi/接口走/ruoyi/prod-api/上传文件走/ruoyi/profile/。前缀统一之后不管后面加多少系统都不会打架。注意前缀尽量用简短、全小写、不带特殊字符的英文单词别用中文或者带横线的长名字。横线在某些 Nginx 变量拼接场景下容易出歧义中文则在 URL 编码上容易翻车。1.3 动手前先把三层路径关系理清楚这是我最想强调的一点。很多人改配置改到崩溃根本原因是脑子里没有一张路径流转图。我给你画一下用文字描述用户浏览器访问https://xxx.com/ruoyi/index.htmlNginx 收到请求匹配/ruoyi/这个 location把请求映射到前端打包产物的目录返回index.html。浏览器解析index.html时里面引用的 JS/CSS 路径必须是/ruoyi/assets/xxx.js否则浏览器会去请求https://xxx.com/assets/xxx.js直接 404 白屏。页面加载完Vue 路由接管。如果用户直接访问https://xxx.com/ruoyi/system/user这个请求是浏览器发出的真实 HTTP 请求会打到 Nginx。Nginx 在/ruoyi/目录下找不到叫system/user的文件所以必须配置try_files把它回退到index.html交给前端路由处理。页面里的接口请求比如登录地址是/ruoyi/prod-api/login。Nginx 匹配到/ruoyi/prod-api/这个 location通过proxy_pass转发给后端 Spring Boot并且把/ruoyi/prod-api这一段剥掉后端收到的实际路径是/login。看清楚了吗一个请求从浏览器到后端路径被改写了两次一次是 Nginx 的目录映射一次是代理转发时的前缀剥离。你改配置的时候脑子里要始终知道当前这一层看到的路径是什么。我见过太多人 Nginx 里写了proxy_pass http://127.0.0.1:8080/带尾斜杠后端又配了context-path: /ruoyi/prod-api结果路径被拼成/ruoyi/prod-api/login打到后端后端只认/login直接 404。这就是没理清层次。2. 前端改造把所有绝对根路径拧回来2.1 打包基础路径的配置Vue3 和 Vue2 位置不同第一刀要切在打包配置上。这一步决定了index.html里引用的资源前缀。如果你用的是 RuoYi-Vue3Vite 构建改vite.config.js// vite.config.js import { defineConfig, loadEnv } from vite export default defineConfig(({ mode }) { const env loadEnv(mode, process.cwd()) return { // 关键部署在 /ruoyi/ 子路径下 base: env.VITE_APP_CONTEXT_PATH || /, // ... 其余配置保持原样 } })如果你用的是老的 RuoYi-VueVue2 vue-cli改vue.config.js// vue.config.js module.exports { // 部署在 /ruoyi/ 子路径下 publicPath: process.env.VUE_APP_CONTEXT_PATH || /, // ... 其余配置保持原样 }base和publicPath做的事情完全一样告诉打包工具我的产物最终会挂在哪一级目录下然后所有自动生成的资源引用都会带上这个前缀。比如设置为/ruoyi/产出的index.html里就会写成script src/ruoyi/assets/index-xxxx.js。我建议别把它写死而是抽到.env.production这类环境变量文件里。原因很简单你本地开发的时候是根路径/生产是子路径/ruoyi/两者必须区分开。如果写死在配置文件里本地npm run dev就会因为资源路径不对而打不开你还得反复改配置很烦。# .env.production VITE_APP_CONTEXT_PATH /ruoyi/注意这里的值必须以/开头、以/结尾。写成ruoyi或者/ruoyi都可能出问题尤其是末尾的斜杠Vite 和浏览器在路径拼接时的容错性不一样加上更保险。2.2 路由 base 必须和打包路径保持一致改完打包配置接下来是路由。RuoYi 前端用的是 Vue Router默认情况下路由的 base 是/。如果你不改它会出现一个很诡异的现象页面能打开因为index.html回来了但是一点菜单跳转就白屏或者跳到错误地址因为路由生成的 URL 是/system/user而不是/ruoyi/system/user。Vue3 Vite 版本的改法// src/router/index.js import { createRouter, createWebHistory } from vue-router const router createRouter({ // 使用环境变量和 base 保持一致 history: createWebHistory(import.meta.env.VITE_APP_CONTEXT_PATH), routes: constantRoutes }) export default routerVue2 版本的改法类似在router/index.js里const router new VueRouter({ mode: history, base: process.env.VUE_APP_CONTEXT_PATH, routes: constantRoutes })这里有个取舍要讲清楚createWebHistory是 history 模式URL 好看但需要 Nginx 配合try_files做兜底createWebHashHistory是 hash 模式URL 里带#不需要服务器兜底但看起来不专业而且带#的链接在某些内嵌 iframe 或者鉴权跳转场景下会被截断。我的建议是既然都上子路径了一般就是正式环境老老实实用 history 模式Nginx 那边多写一行try_files就行别图省事用 hash。2.3 axios 的接口前缀要单独处理别和路由混为一谈这是最容易搞混的一处。路由 base 管的是前端页面地址axios 的baseURL管的是接口请求地址。两者可以一样也可以不一样取决于你 Nginx 怎么配。RuoYi 前端在src/utils/request.js里创建 axios 实例// src/utils/request.js const service axios.create({ // 用环境变量别写死 baseURL: import.meta.env.VITE_APP_BASE_API, timeout: 10000 })然后.env.production里配置VITE_APP_BASE_API /ruoyi/prod-api这样前端发登录请求时真实地址就是/ruoyi/prod-api/login。接下来 Nginx 只要把这个前缀正确处理掉即可。这里我想强调的是不要把VITE_APP_BASE_API设成完整的https://xxx.com/ruoyi/prod-api。用相对路径有两个好处一是本地开发时可以通过 Vite 的 proxy 直接代理不用改代码二是生产环境换域名时不用重新打包。用完整域名的话一旦域名变了你得整个前端重新构建纯属给自己找麻烦。2.4 几个容易被忽略的静态资源引用改完上面三项90% 的情况就正常了。但剩下 10% 会让你抓狂因为它们藏在代码角落里。我踩过的有这几个第一public/index.htmlVue2或者根目录index.htmlVite里手写的link和script。RuoYi 默认的index.html里一般有 favicon 引用如果你写的是/favicon.ico在子路径下就会 404。正确写法是link relicon href/ruoyi/favicon.ico或者直接交给打包工具处理用相对路径。第二CSS 里引用的背景图。用background: url(/images/bg.png)这种绝对路径的子路径下必然挂掉。要么改成相对路径url(../assets/bg.png)要么用变量拼前缀。我建议直接改用相对路径或者~/assets/这种别名写法让打包工具去处理。第三字体图标iconfont的 CSS。RuoYi 里大量用了图标字体它的 CSS 里会有url(data:...)或者url(./iconfont.woff)。如果是在src/assets里通过 import 引入的一般没问题但如果是放在public目录里用绝对路径引的就要注意了。第四动态import()的 chunk 路径。Vite 和 webpack 会自动处理只要你base配对了就没问题。但如果你手写了import(/src/views/xxx.vue)这种带绝对路径的动态导入就会出问题。好消息是正常项目不会这么写。实操心得改完前端别急着部署本地npm run build之后用npx serve dist起个静态服务或者直接开浏览器的开发者工具看 Network 面板。先看index.html里引用的 js 路径对不对再看有没有 404。这一步能提前发现 80% 的路径问题比部署到服务器上再排查高效得多。3. Nginx 配置alias 与 root 的一线之差3.1 location 匹配规则和尾部斜杠的门道到了 Nginx 这一层是整件事最容易出错的地方。我先说一个几乎所有人都踩过的坑root和alias的行为差异。假设你的前端产物放在/data/www/ruoyi/目录下里面有index.html、assets/等。用 root 的写法location /ruoyi/ { root /data/www; try_files $uri $uri/ /ruoyi/index.html; }Nginx 收到/ruoyi/assets/index.js请求时会把root的值和完整 URI 拼起来也就是/data/www/ruoyi/assets/index.js/data/www/ruoyi/assets/index.js。所以你的产物要放在/data/www/ruoyi/下。用 alias 的写法location /ruoyi/ { alias /data/www/ruoyi/; try_files $uri $uri/ /ruoyi/index.html; }Nginx 收到/ruoyi/assets/index.js时会把 location 匹配到的部分/ruoyi/替换成 alias 的值也就是/data/www/ruoyi/assets/index.js/data/www/ruoyi/assets/index.js。产物直接放在/data/www/ruoyi/下和 root 写法殊途同归。看起来两者最终指向同一个文件但关键区别在于location的值必须以/结尾alias的值也必须以/结尾。任何一边少了斜杠路径拼接就会错位。比如alias /data/www/ruoyi;没有尾斜杠那么/ruoyi/assets/index.js会被映射成/data/www/ruoyiassets/index.js文件当然找不到直接 404。这个错误我第一次遇到的时候盯着配置看了二十分钟死活没看出来。我的个人习惯是前端静态资源用root因为语义更符合直觉出错的概率更低。alias我一般只在需要做目录名和 URI 不一致的映射时才用比如location /static/ { alias /data/upload/images/; }。3.2 try_files 为什么是前端路由的救命稻草配置完静态资源第二个必须处理的是前端路由的刷新问题。用户在/ruoyi/system/user页面上按 F5浏览器会向 Nginx 请求/ruoyi/system/user这个真实地址。Nginx 一看我目录里没有叫system/user的文件啊直接返回 404。这就是刷新 404的根源。try_files就是解决这个的try_files $uri $uri/ /ruoyi/index.html;它的执行逻辑是先试着找请求的 URI 对应的文件$uri找不到就试着找目录$uri/还找不到就内部重定向到/ruoyi/index.html。这样无论用户访问哪个前端路由最终都会拿到index.html然后由 Vue Router 根据 URL 渲染对应页面。这里有个细节要注意回退目标/ruoyi/index.html里的/ruoyi前缀必须带上。如果你写成/index.htmlNginx 会去根目录找而根目录下大概率没有这个文件因为你部署在子路径结果还是 404。这个坑我也踩过表现形式是首页正常刷新就 404。注意某些情况下$uri/会导致目录被当成文件处理如果你确定前端产物里没有需要目录索引的目录可以简写成try_files $uri /ruoyi/index.html;。我一般两个都留着问题不大。3.3 后端接口代理与路径剥离的两种写法前端静态资源和路由搞定后接下来是接口代理。这一步的核心问题是要不要把/ruoyi/prod-api这段前缀剥掉再转发给后端方案一剥离前缀。Nginx 用带尾斜杠的proxy_pass。location /ruoyi/prod-api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }注意proxy_pass http://127.0.0.1:8080/;末尾这个斜杠非常关键。它的含义是把 location 匹配的部分/ruoyi/prod-api/替换成/所以/ruoyi/prod-api/login转发给后端就变成了/login。这种方式下后端不需要做任何路径改动server.servlet.context-path保持默认的空值即可。方案二不剥离前缀。proxy_pass不带尾斜杠。location /ruoyi/prod-api/ { proxy_pass http://127.0.0.1:8080; # ... }这种情况下/ruoyi/prod-api/login会原样转发给后端变成/ruoyi/prod-api/login。那后端就必须配置server.servlet.context-path: /ruoyi/prod-api才能接住。两种方案都行但我的强烈建议是选方案一。理由有三一是后端保持干净本地开发时不用配 context-path减少环境差异二是如果哪天你要换前缀比如从/ruoyi/prod-api改到/api只改 Nginx 一处就行后端不用动三是 Spring Boot 的 context-path 一旦设置会影响所有内部路径包括 Swagger、 actuator 等容易引发新问题。我再补充一个容易忽略的细节路径重写还可能涉及 Cookie 的 path。如果后端下发的 Cookie 里带了Path/浏览器会把它存到根路径下多系统共享域名时会互相污染。你可以在 Nginx 里用proxy_cookie_path调整proxy_cookie_path / /ruoyi/prod-api/;不过说实话RuoYi 前端默认是把 token 存 localStorage 的不太依赖 Cookie。如果你的系统改了默认行为、用了 Cookie 鉴权那这一行就该加上。3.4 一份可以直接抄的完整配置把上面几块拼起来一份完整的 RuoYi 子路径部署配置长这样server { listen 443 ssl; server_name xxx.com; ssl_certificate /etc/nginx/cert/xxx.pem; ssl_certificate_key /etc/nginx/cert/xxx.key; # 1. 前端静态资源 路由兜底 location /ruoyi/ { root /data/www; index index.html; try_files $uri $uri/ /ruoyi/index.html; } # 2. 后端接口代理剥离 /ruoyi/prod-api 前缀 location /ruoyi/prod-api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 300s; client_max_body_size 50m; } # 3. 上传文件访问RuoYi 默认 profile 目录 location /ruoyi/profile/ { alias /data/ruoyi/uploadPath/; expires 7d; } }关于这段配置我解释几个当初特意加上的参数。proxy_read_timeout 300s是给导出 Excel、批量操作这类长耗时接口留的余地。Nginx 默认 60 秒RuoYi 的导出接口在大数据量下很容易超然后就报 504。这个值我一般设置成 300 秒基本够用。client_max_body_size 50m是上传文件大小限制。Nginx 默认 1MRuoYi 里传个稍微大点的附件就报 413。前面提到过nginx请求体大小限制就是这个参数。50M 是个比较通用的值如果你的业务涉及视频或者大附件可以调到 200M但记得同时也要看 Spring Boot 的spring.servlet.multipart.max-file-size配置两边要一起改。上传文件的 location 用alias是因为 URI 前缀/ruoyi/profile/和实际物理目录名uploadPath不一样这时候alias更直观。4. 后端侧需要同步调整的地方4.1 context-path 到底要不要动前面说过如果 Nginx 采用剥离前缀的方案Spring Boot 的 context-path 就不用改保持默认。但现实中我确实遇到过必须改 context-path 的场景比如客户的运维死活不给改 Nginx只给了个 location 直通那你就只能在后端加 context-path 来对齐。如果确实要加改application.ymlserver: port: 8080 servlet: context-path: /ruoyi/prod-api改动虽小但会引发一串连锁反应你得同步处理第一Swagger 的文档地址会从/swagger-ui.html变成/ruoyi/prod-api/swagger-ui.html如果你在前端或者接口文档里写死了旧地址需要改。第二如果有其他服务通过 HTTP 调用这个后端调用方的前缀也得加。第三健康检查、监控端点actuator的地址会变如果运维那边配了探针会检测失败。第四也是最容易忽略的RuoYi 里的文件上传返回的 URL 有可能是相对路径也可能是绝对路径加了 context-path 之后这些 URL 的拼接逻辑可能会导致访问 404。这个要实际测一遍。所以你看context-path 这个改动看着简单影响面却很大。这也是我前面推荐方案一的原因——把路径处理的复杂度尽量收拢到 Nginx 这一层后端保持稳定。4.2 文件上传与图片回显路径的适配RuoYi 默认的上传目录是这么配的ruoyi: profile: /data/ruoyi/uploadPath后端把文件存到这个物理目录同时数据库里存的是访问 URL比如/profile/upload/2024/01/01/xxx.png。前端拿到这个 URL 直接拼到页面上显示请求地址就变成了https://xxx.com/profile/upload/...——注意前缀没了/ruoyi而且这个请求会打到 Nginx 的根路径根本匹配不到你配的/ruoyi/profile/location结果就是图片裂开。处理方式有三种我按推荐度排个序其一找到 RuoYi 里生成资源 URL 的地方一般在ResourcesConfig和FileUploadUtils里加上/ruoyi前缀。具体代码大概是这样// 修改资源前缀映射 registry.addResourceHandler(/ruoyi/profile/**) .addResourceLocations(file: RuoYiConfig.getProfile() /);这需要改工具类里生成 URL 的那段逻辑把/profile改写成/ruoyi/profile。改动点比较集中一次改完一劳永逸。其二在 Nginx 里额外加一个 location把/profile/也映射过去不依赖前缀location /profile/ { alias /data/ruoyi/uploadPath/; }这个办法不用改代码但缺点是把路径暴露在根目录下多系统共用域名的时候容易撞车而且不够规范。其三前端在拼接图片 URL 时统一加前缀。这个最不推荐因为散落各处容易漏。我个人选第一种。虽然要动后端代码但语义最清楚维护起来最省心。4.3 验证码、WebSocket 与其他杂项还有几个小地方容易漏我列一下验证码接口。RuoYi 的验证码是/captchaImage这个接口返回 Base64 图片不走静态资源所以只要接口代理正常就没问题。但如果你的项目改成了验证码图片走独立接口返回二进制流的实现那个接口地址也要在前缀里。WebSocket。如果你的 RuoYi 集成了 WebSocket 做消息推送很多二次开发项目会加Nginx 代理需要额外的 headerlocation /ruoyi/prod-api/ws/ { proxy_pass http://127.0.0.1:8080/ws/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_read_timeout 3600s; }注意Connection upgrade这里的引号有些版本的 Nginx 不写引号会报语法错误。还有proxy_read_timeout要设大否则连接空闲一会儿就被断开前端表现是消息推送时好时坏。定时任务和文件下载。这些走的是普通 HTTP只要接口代理对了就没事。但如果你的下载接口是直接返回文件流并且前端用了window.open要确认打开的 URL 也带上了正确前缀。第三方回调地址。比如对接了消息推送、短信、支付这类需要配置回调地址的功能回调地址一定要写完整的公网地址含子路径否则对方服务器访问不到。5. 常见问题排查速查表5.1 白屏和静态资源 404 的排查思路白屏几乎是子路径部署的第一道关。我总结的排查顺序是先按 F12 打开开发者工具看 Console 面板有没有红色的报错。如果是Uncaught SyntaxError: Unexpected token 基本可以断定是 JS 文件被返回成了 HTML也就是请求 JS 时被try_files兜底到了index.html原因是静态资源路径不对。再看 Network 面板找那几个 404 的请求看它们的实际 URL。如果请求的是https://xxx.com/assets/xxx.js没有/ruoyi前缀那就是打包base没配对回去改vite.config.js。如果请求的是https://xxx.com/ruoyi/assets/xxx.js但还是 404那就是 Nginx 的文件目录映射错了检查root或alias的路径。还有一种情况是 200 但内容不对。返回的 JS 内容是一段 HTML这也是try_files兜底的典型症状——因为 Nginx 找不到文件按你配的规则回退到了index.html结果浏览器拿到 HTML 当 JS 解析直接报语法错误。现象最可能的原因排查位置完全白屏Console 报语法错误JS 被回退成 index.html检查静态资源路径和 try_files页面框架出来了但样式全无CSS 路径错误检查 publicPath/base图片、字体图标裂开绝对路径引用检查 CSS 里的 url()首页正常菜单点击后空白路由 base 不对检查 router 的 base 配置接口全部 404代理前缀不对检查 proxy_pass 尾斜杠接口 401 或登录后掉线Cookie/Token 路径问题检查 proxy_cookie_path5.2 接口 404 与登录态异常的定位方法接口 404 的排查我一般会打开 Network找一个失败请求看两样东西请求 URL和响应内容。请求 URL 应该长这样https://xxx.com/ruoyi/prod-api/login。如果它长成https://xxx.com/prod-api/login说明前端VITE_APP_BASE_API没配/ruoyi前缀。如果请求 URL 对了但返回的响应体是 Nginx 的 404 页面HTML说明 Nginx 没匹配到这个 location检查 location 写法注意结尾的斜杠。如果响应是 Spring Boot 返回的 JSON说明请求到了后端但路径不对这时候去后端日志里看实际接收到的 URI和你的预期对比。登录态异常通常有两种表现一是登录成功但马上又跳回登录页二是刷新页面后掉线。第一种多半是 token 存进去了但请求没带上检查 axios 拦截器第二种如果用的是 Cookie 存 token那就要看proxy_cookie_path有没有配对。多系统共用域名时两个系统的 Cookie 同名会互相覆盖这个坑很隐蔽表现为登录 A 系统之后B 系统的登录状态就没了。5.3 刷新 404 的两种成因刷新 404 在我看来只有两个原因定位起来很快。第一种try_files没配或者配错了。特别是回退目标路径写错少了子路径前缀的情况。这时候的典型特征是首页能打开点进去的页面能看但只要在深层路由上刷新就 404。第二种try_files配了但首页本身访问也是 404。这说明静态资源目录映射就有问题属于更基础的问题回去看root/alias。还有一种比较刁钻的情况try_files配对了但请求经过了一层 CDN 或者前置代理那层没做路径透传把请求改写了。这种排查起来要一层一层看先确认打到 Nginx 的原始 URI 是什么。可以在 location 里临时加一行add_header X-Debug-Uri $request_uri;通过响应头看看 Nginx 到底收到了什么路径。5.4 一些零碎但高频的坑坑一Nginx 配置改完没生效。大概率是没 reload。改完配置记得nginx -t测试语法然后nginx -s reload。如果 reload 报错看错误日志/var/log/nginx/error.log。坑二权限问题导致的 403。Nginx 的 worker 进程通常以www-data或nginx用户运行如果你的静态资源目录权限是root:root 700Nginx 读不到返回 403。用chmod -R 755和chown处理一下。坑三SELinux 拦截。在 CentOS 或 RHEL 系系统上SELinux 开着的时候Nginx 访问非标准目录会被拦截报 403 但日志里看不出明显原因。可以临时用setenforce 0验证如果是这个原因再用semanage fcontext正确配置策略别直接永久关 SELinux。坑四缓存导致改了没效果。前端打包后的文件名带 hash一般没问题。但index.html本身如果被浏览器强缓存了你部署新版本后用户还是拿到旧的index.html引用的还是旧资源。在 Nginx 里给index.html单独设置不缓存location /ruoyi/index.html { add_header Cache-Control no-cache, no-store, must-revalidate; }坑五接口返回 413。前面提过client_max_body_size默认 1M上传大文件会 413。这个报错在前端有时候显示不出来只在 Network 里能看到容易误判成上传接口坏了。6. 实操心得与上线检查清单6.1 上线前我会逐条过的检查项这套配置我在几个项目上复用过现在已经整理成固定清单了每次上线前照着走一遍基本不会出问题。第一项生产环境打包时确认base/publicPath已经是子路径值。检查方法打开产物的index.html看里面的script和link标签每个路径都必须带/ruoyi/。第二项router的 base 和打包 base 一致。检查方法本地起静态服务点几个菜单看 URL 有没有正确带上前缀。第三项Nginxlocation和alias/root的斜杠都齐全。检查方法nginx -t之后用curl -I https://xxx.com/ruoyi/看返回头是不是 200。第四项try_files兜底路径写全了。检查方法curl -I https://xxx.com/ruoyi/system/user应该返回 200 而不是 404。第五项接口代理的proxy_pass尾斜杠和 location 规则匹配。检查方法curl -X POST https://xxx.com/ruoyi/prod-api/login看能不能到后端。第六项文件上传和回显。检查方法上传一张图看返回的 URL 是否能正常访问。这一步最容易被漏掉因为很多人只测了登录和列表没测上传。第七项刷新测试。在每个主要路由上按 F5确保都能正常加载。第八项多系统共存测试。如果你是在多系统的环境下部署登录 A 系统后再登录 B 系统回头确认 A 的登录态是否还在。6.2 我踩过的几个坑和一个偷懒技巧说几个印象很深的实际的坑。有一次折腾了两个小时配置怎么看都对但接口一直 404。最后发现是proxy_pass那行http://127.0.0.1:8080/末尾的斜杠被同事顺手删了——他觉得斜杠多余。就这一个字符导致所有接口路径都多了一层前缀。从那以后我在配置里都会给关键行加注释写清楚这个斜杠不能删删了接口全 404。还有一次是前端改了base但打包时用的是旧的dist目录。Vite 默认输出到dist如果你不先rm -rf dist再 build有时候会残留旧文件表现是新旧文件混在一起路径时对时错非常迷惑。所以我现在打包前都习惯先清一次目录CI 里也是这么配的。关于偷懒技巧分享一个如果你要在本地模拟子路径环境不用真起 Nginx。Vite 本身可以通过配置server.base来模拟或者更简单用npx serve加--single参数模拟 history 兜底。这样你可以在本地就把路径问题排查完不用每次改配置都上传服务器。# 本地模拟子路径部署 npx serve dist --single --listen 3000 # 然后访问 http://localhost:3000/ruoyi/ 验证不过要注意npx serve模拟的目录映射和 Nginx 的alias行为不完全一样它更接近root的行为。所以本地验证通过只能说明前端部分没问题Nginx 那层还是要实际部署后验证一遍。最后再补一个我个人的配置习惯。现在我在每个项目的 Nginx 配置里都会在文件顶部加一段注释写清楚部署路径、前端产物目录、后端端口、上传目录这四个关键信息。原因很简单这套配置可能半年后才需要改到时候你早忘了当时怎么设计的有注释能省很多回忆时间。而且如果是同事接手这段注释能让他五分钟看懂整个结构比看代码猜强太多了。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →