ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

若依前后端分离部署常见问题排查指南

若依前后端分离部署常见问题排查指南 简介本资源是一份面向Java全栈开发者与运维人员的若依RuoYi前后端分离项目实战部署指南聚焦LinuxNginx与WindowsTomcat双环境落地难点系统解决部署后404页面、跨域调用第三方API如百度地图等高频问题。文档以实操为导向完整覆盖后台jar/war包构建、前端dist目录部署、Redis缓存配置、Nginx反向代理设置、Tomcat Context路径定制及web.xml容错配置等关键环节并附Vue路由路径修正、CORS策略配置等排错细节。资源为1个223KB的Word文档.docx结构清晰、图文结合含命令示例、配置代码片段与典型错误归因分析便于快速查阅与现场实施。目前已有7766人学习下载适合刚接触若依框架、需独立完成生产环境部署的中初级开发者高效上手。1. “菜单打不开”“登录后空白页”“404 刷不出来”——若依前后端分离部署里最玄学的三连击90% 的人卡在这三步就放弃重装你刚把若依RuoYi前后端分离版打包好scp 传到服务器、nohup 启动 jar、nginx reload 完毕浏览器输入http://xxx.xxx.xxx.xxx—— 登录页出来了输入账号密码一按回车页面白了。F5 刷新404。点左侧菜单没反应控制台报Failed to load resource: the server responded with a status of 404 (Not Found)。再查 nginx 日志全是*1 open() /usr/share/nginx/html/profile/xxxx failed (2: No such file or directory)。你翻遍文档、搜遍论坛有人说改vue.config.js有人说加web.xml有人说删掉publicPath前面的点有人说要配history模式 fallback……越试越乱最后默默删库重来。这不是你技术不行是若依这套部署链路里埋了三个「默认不报错但必然失效」的隐性断点前端路由模式与服务端静态资源路径不匹配、Nginx 未正确处理 history 跳转、Tomcat 对单页应用SPA的 404 没兜底。这篇笔记不讲“怎么安装 Redis”只聚焦这三类高频翻车现场——它们不是配置错误而是若依作为一套真实生产级框架在脱离开发环境npm run serve后对部署侧提出的明确契约要求。如果你正被“菜单加载失败”“空白页”“跨域 404”反复暴击这篇就是你的后悔药。2. 登录成功但菜单空白/跳转 404Vue Router history 模式 Nginx 静态服务的致命错配若依前端基于 Vue Router默认启用history模式非hash模式这意味着 URL 是/system/user而非/#/system/user。好处是美观、SEO 友好坏处是——所有非根路径的请求都必须由前端接管否则服务端会当成真实文件路径去查找找不到就 404。而 Nginx 默认行为正是收到/system/user请求就去root /usr/share/nginx/html;目录下找system/user/index.html这个文件。它当然不存在于是返回 404。此时 Vue Router 根本没机会启动更别说渲染菜单了。这不是前端代码 bug是服务端没履行“把所有非 API 请求都 fallback 到index.html”的约定。2.1 根因深挖为什么location /块里不加try_files就必然白屏看若依文档里那句轻描淡写的“修改 nginx.conf”很多人只改了proxy_pass代理后端 API却漏掉了最关键的location /块配置。标准 Nginx 配置中location /控制所有以/开头的请求。若此处仅写location / { root /usr/share/nginx/html; index index.html; }Nginx 会严格按字面路径查找文件/system/user→ 查/usr/share/nginx/html/system/user→ 无此目录 → 404。而 Vue Router 的history模式要求只要请求不是.js/.css/.png等静态资源且不是/prod-api/这类 API 前缀就一律返回index.html让前端 JS 自己解析路由。这个逻辑必须由try_files指令实现。2.2 正确解法Nginx 必须启用try_filesfallback机制在nginx.conf的server块内找到或新增location /配置彻底替换为以下内容注意这是唯一生效方案别再抄网上残缺片段location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; }逻辑说明try_files指令按顺序尝试匹配$uri如/system/user、$uri/如/system/user/若都失败则强制返回/index.html即前端入口文件。这样无论用户直接访问/、/system/user还是刷新页面Nginx 都返回index.htmlVue Router 才能初始化并根据 URL 渲染对应组件。参数说明$uri是原始请求 URI不含 query string$uri/是加斜杠的目录形式/index.html是 fallback 路径必须以/开头表示相对于root的绝对路径。若root设为/data/www则实际返回/data/www/index.html。2.3 验证是否生效三步快速自检检查 Nginx 配置语法执行sudo nginx -t输出syntax is ok且test is successful才算通过确认静态文件位置ls -l /usr/share/nginx/html/必须能看到index.html、favicon.ico、js/、css/等文件即你复制的dist目录内容抓包验证响应体用浏览器开发者工具 Network 面板访问/system/user查看 Response Headers 中Content-Type是否为text/htmlResponse Body 是否包含div idapp—— 若是说明 Nginx 成功 fallback 到index.html若仍是 404 或返回空说明location /配置未生效或路径错误。2.4 避坑常见问题与血泪经验现象改完nginx.confnginx -s reload后依然 404原因nginx.conf中存在多个location /块比如location / { ... }和location /prod-api { ... }并存Nginx 优先匹配最长前缀若/prod-api块写在/块前面且未加^~修饰符可能导致/system/user被错误匹配到 API 块。解决确保location /是最外层、最宽泛的块且放在所有具体路径如/prod-api、/static之后或给 API 块加^~强制前缀匹配location ^~ /prod-api { ... }。现象Nginx 返回index.html但控制台报GET http://ip/js/app.xxx.js net::ERR_ABORTED 404原因前端构建时publicPath配置错误导致生成的index.html中 JS/CSS 路径指向/js/app.xxx.js但 Nginx 的root指向/usr/share/nginx/html实际文件在/usr/share/nginx/html/dist/js/下。解决部署前必须修改vue.config.js中的publicPath// vue.config.js module.exports { publicPath: ./, // 关键改为相对路径而非 / 或 /prod/ }注意./表示相对于index.html当前目录这样生成的index.html里script src./js/app.xxx.js才能正确加载。若设为/路径变成绝对根路径/js/...Nginx 会在root根目录下找而非dist子目录。现象try_files配置正确但访问/profile/avatar若依头像上传路径仍 404原因若依后端默认将用户头像存于profile/目录如profile/avatar/xxx.png该路径属于静态资源需单独配置location让 Nginx 直接提供而非 fallback 到index.html。解决在server块内添加独立locationlocation /profile/ { alias /home/ruoyi/ruoyi-admin/profile/; # 替换为你的实际 profile 目录绝对路径 expires 1d; add_header Cache-Control public, immutable; }alias与root区别alias会完全替换匹配的路径前缀/profile/avatar.png→ 映射到/home/ruoyi/.../avatar.pngroot是拼接/profile/avatar.png→/home/.../profile/avatar.png。此处必须用alias否则多一层profile。3. Windows Tomcat 部署后空白页Tomcat 对 SPA 的 404 处理缺失当选择 Windows Tomcat 方案时若依文档指导你把dist目录整个丢进webapps再改server.xml加Context。但很多人忽略了一个残酷事实Tomcat 本质是 Servlet 容器不是静态文件服务器它对index.html以外的路径如/system/user默认不识别直接返回 404且不会像 Nginx 那样提供try_files机制。你看到的空白页正是 Tomcat 在webapps/dist/下找不到/system/user这个“Servlet”或“JSP”时抛出的标准 404 页面或空白。而若依前端需要的是所有 404 都重定向到index.html交由 Vue Router 处理。3.1 根因深挖为什么web.xml是 Tomcat 下 SPA 的唯一救命稻草Tomcat 的web.xml是 Web 应用的部署描述符其中error-page元素允许你定义特定 HTTP 状态码的自定义响应。若依文档让你新建WEB-INF/web.xml并配置error-page其核心逻辑是当 Tomcat 内部找不到请求路径时不返回默认 404 页面而是转发forward到/index.html。这相当于在 Tomcat 层面实现了 Nginx 的try_files功能。没有它任何非根路径的直接访问或刷新都会触发 Tomcat 的 404 流程前端 JS 根本没机会运行。3.2 正确解法web.xml必须精准配置 error-page forward在dist目录下创建WEB-INF文件夹注意大小写并在其中新建web.xml内容必须严格如下XML 声明和命名空间不可省略?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 metadata-completetrue display-nameVue SPA Fallback/display-name error-page error-code404/error-code location/index.html/location /error-page /web-app逻辑说明error-page告诉 Tomcat当发生 HTTP 404 错误时不要返回默认错误页而是内部 forward 到/index.html注意是/开头的路径表示相对于当前 Web 应用根目录。Tomcat 会读取dist/index.html并返回Vue Router 得以启动。参数说明version4.0对应 Servlet 4.0 规范Tomcat 9若用 Tomcat 8请改为3.1并调整xsi:schemaLocation中的 URLmetadata-completetrue告诉容器无需扫描注解提升启动速度。3.3 验证是否生效两步定位 Tomcat 是否接管 404检查web.xml位置与权限确保文件位于dist/WEB-INF/web.xml不是dist/WEB-INF/外层且 Tomcat 启动用户对该文件有读取权限Windows 下通常无问题观察 Tomcat 日志启动 Tomcat 后访问一个不存在的路径如/fake/path查看logs/catalina.out或logs/localhost.date.log若看到类似Forwarding to error page from request [...]的日志说明web.xml生效若只有Processing ErrorPage[errorCode404, location/index.html]但无后续可能是location路径错误。3.4 避坑常见问题与血泪经验现象web.xml已添加但访问/system/user仍返回 Tomcat 默认 404 页面带 Apache Tomcat 字样原因location值写成了index.html缺少/前缀导致 Tomcat 尝试在WEB-INF目录下找index.html自然失败。解决location必须以/开头如/index.html表示应用根目录下的文件。现象web.xml生效但index.html加载后控制台报Uncaught SyntaxError: Unexpected token 原因index.html中引用的 JS/CSS 路径错误。Tomcat 将dist目录作为 Web 应用根所以publicPath必须设为./相对路径而非/绝对根路径。若设为/index.html会请求http://ip:8080/js/app.xxx.js但 Tomcat 实际将dist/js/映射到http://ip:8080/js/路径不匹配。解决再次确认vue.config.js中publicPath: ./重新npm run build:prod覆盖dist目录。现象web.xml配置正确但登录后点击菜单仍跳转失败Network 面板显示GET http://ip:8080/system/user 404原因Tomcat 的Context配置未生效或dist目录未正确部署到webapps。若dist目录名为myapp则 Tomcat 会将其部署为http://ip:8080/myapp/此时所有请求路径应为/myapp/system/user但前端router默认 base 是/导致请求发往根路径。解决在vue.config.js中显式设置baseUrlVue CLI 2或publicPathVue CLI 3为应用上下文路径// vue.config.js (Vue CLI 3) module.exports { publicPath: /myapp/, // 与 Tomcat 部署的 Context Path 一致 }注意publicPath改为/myapp/后index.html中所有资源路径会自动加上/myapp/前缀如script src/myapp/js/app.xxx.js确保 Tomcat 能正确路由。4. 跨域问题百度地图等第三方 API 调用失败的三种真实场景与解法若依项目常需集成百度地图、高德地图、微信 JS-SDK 等第三方服务这些 API 通常要求调用方域名在白名单内。而开发时npm run serve启动的http://localhost:80与生产环境http://your-server-ip域名不同浏览器会拦截跨域请求控制台报CORS header Access-Control-Allow-Origin missing或No Access-Control-Allow-Origin header is present。这不是若依的锅是浏览器同源策略的刚性约束。但解决方案不能只靠“让后端加 CORS”因为第三方 API 的响应头由对方服务器控制你无法修改。4.1 根因深挖为什么“后端加 CrossOrigin”对第三方 API 无效CrossOrigin注解Spring Boot或CorsConfiguration是后端服务自己响应时添加Access-Control-Allow-Origin头用于解决前端 → 若依后端的跨域。但当你在前端 JS 中直接fetch(https://api.map.baidu.com/...)请求是前端 → 百度服务器百度服务器的响应头里没有Access-Control-Allow-Origin: *或你的域名浏览器就会拒绝。此时若依后端加再多CrossOrigin也无济于事因为请求根本没经过若依后端。4.2 正确解法必须走“后端代理”绕过浏览器同源限制唯一可靠方案是前端请求若依后端的一个代理接口如/proxy/baidu若依后端收到请求后用自己的服务器身份去调用百度 API再把结果原样返回给前端。这样前端只与同源的若依后端通信无跨域若依后端与百度通信服务器间无同源限制。这需要两步改造第一步前端配置代理开发期与统一接口生产期开发期npm run serve利用 Vue CLI 的devServer.proxy将/proxy/baidu请求代理到若依后端// vue.config.js devServer: { proxy: { /proxy/baidu: { target: http://localhost:8080, // 若依后端地址 changeOrigin: true, pathRewrite: { ^/proxy/baidu: /baidu // 将 /proxy/baidu/xxx 重写为 /baidu/xxx } } } }生产期部署后前端代码中所有调用百度 API 的地方必须改为请求若依后端的代理接口例如// 原始错误写法跨域 // fetch(https://api.map.baidu.com/geocoding/v3/?address北京outputjsonakxxx) // 正确写法走若依代理 fetch(/prod-api/baidu/geocoding/v3/?address北京outputjsonakxxx)第二步后端实现代理 Controller若依 Spring Boot在若依后端项目中新建一个 Controller负责转发请求// com.ruoyi.common.controller.ProxyController.java RestController RequestMapping(/baidu) public class ProxyController { private static final String BAIDU_API_BASE https://api.map.baidu.com; GetMapping(/{path:.}) public ResponseEntity? proxyBaidu( PathVariable String path, RequestParam MapString, String params, HttpServletRequest request) throws IOException { // 构建完整百度 API URL String url BAIDU_API_BASE / path ? buildQueryString(params); // 使用 RestTemplate 发起 GET 请求生产环境建议用 WebClient 或 OkHttp RestTemplate restTemplate new RestTemplate(); HttpHeaders headers new HttpHeaders(); headers.set(User-Agent, Mozilla/5.0); HttpEntityString entity new HttpEntity(headers); try { ResponseEntityString response restTemplate.exchange( url, HttpMethod.GET, entity, String.class); return ResponseEntity.status(response.getStatusCode()) .headers(response.getHeaders()) .body(response.getBody()); } catch (Exception e) { return ResponseEntity.status(500).body(Proxy failed: e.getMessage()); } } private String buildQueryString(MapString, String params) { return params.entrySet().stream() .map(e - e.getKey() URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8)) .collect(Collectors.joining()); } }逻辑说明该 Controller 拦截所有/baidu/**请求提取路径和查询参数拼成百度 API 完整 URL再用RestTemplate以服务器身份发起请求并将百度的响应状态码、Header、Body 原样透传给前端。参数说明PathVariable String path匹配任意子路径如geocoding/v3RequestParam MapString, String自动收集所有 query 参数buildQueryString确保参数值 URL 编码避免特殊字符如中文导致百度 API 解析失败。4.3 避坑常见问题与血泪经验现象代理接口返回 400 或 500百度 API 响应{status:3,message:Invalid request}原因百度 API 的ak密钥参数未正确传递或ak值在若依后端被 URL 编码两次前端已编码后端又编码一次。解决在buildQueryString中只对e.getValue()编码且确保前端传参时ak是原始字符串不手动编码或改用UriComponentsBuilder更安全UriComponentsBuilder builder UriComponentsBuilder.fromHttpUrl(url); params.forEach(builder::queryParam); String fullUrl builder.toUriString(); // 自动处理编码现象代理请求成功但返回的 JSON 中content-type是text/plain前端fetch().json()报错原因百度 API 响应头Content-Type可能是text/plain;charsetutf-8而RestTemplate默认不识别返回String类型。解决在RestTemplate请求中显式指定StringHttpMessageConverter支持text/plainRestTemplate restTemplate new RestTemplate(); ListHttpMessageConverter? converters new ArrayList(); converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8)); converters.add(new MappingJackson2HttpMessageConverter()); restTemplate.setMessageConverters(converters);现象本地开发代理正常但部署到 Linux 后/prod-api/baidu/...返回 404原因Nginx 配置中/prod-api代理规则未覆盖/prod-api/baidu路径或location /prod-api块内缺少proxy_pass指向后端。解决检查nginx.conf中location /prod-api块确保proxy_pass指向正确的后端地址如http://127.0.0.1:8080且无^~修饰符导致路径截断。5. 启动失败/后台进程消失nohup java -jar的隐形陷阱与健壮守护方案若依文档推荐用nohup java -jar ruoyi-admin.jar msg.log 21 启动后端看似简单实则暗藏三大隐患日志文件无限增长撑爆磁盘、Java 进程意外退出后无人拉起、nohup无法管理进程生命周期无法优雅停止。某次服务器重启后你发现ps aux | grep ruoyi没有进程msg.log里最后一行是OutOfMemoryError但没人知道它何时挂的。这不是运维疏忽是nohup作为 shell 工具根本不具备服务化管理能力。5.1 根因深挖为什么nohup不是生产环境的正确答案nohup的设计初衷是让命令在终端关闭后继续运行它只是简单地将stdout和stderr重定向到nohup.out或你指定的文件然后fork一个子进程执行命令。它不监控进程健康状态、不处理内存溢出、不记录启动/停止时间、不提供服务启停脚本。在生产环境中若依后端可能因 GC 压力、数据库连接池耗尽、Redis 连接超时等原因崩溃nohup不会感知更不会重启。你只能靠定时巡检日志效率极低。5.2 正确解法用systemd替代nohup实现真正的服务化Linux 系统推荐使用systemd现代发行版标配来管理 Java 服务。它提供进程守护、自动重启、日志聚合、依赖管理等企业级能力。步骤如下第一步创建 systemd 服务文件sudo vim /etc/systemd/system/ruoyi-admin.service填入以下内容请根据你的实际路径修改[Unit] DescriptionRuoyi Admin Service Afternetwork.target redis.service Wantsredis.service [Service] Typesimple Userruoyi WorkingDirectory/home/ruoyi/ruoyi-admin ExecStart/usr/bin/java -Xms512m -Xmx1024m -Dfile.encodingUTF-8 -jar /home/ruoyi/ruoyi-admin/ruoyi-admin.jar Restartalways RestartSec10 SuccessExitStatus143 StandardOutputjournal StandardErrorjournal SyslogIdentifierruoyi-admin [Install] WantedBymulti-user.target逻辑说明[Unit]定义服务依赖启动前确保网络和 Redis 就绪[Service]是核心Typesimple表示主进程即 Java 进程Userruoyi指定非 root 用户运行安全最佳实践ExecStart是启动命令-Xms/-Xmx设置 JVM 内存Restartalways确保进程崩溃后自动重启StandardOutputjournal将日志接入systemd日志系统无需手动管理msg.log。参数说明RestartSec10表示重启间隔 10 秒SuccessExitStatus143将SIGTERM优雅停止的退出码视为成功避免systemctl stop后被误判为失败重启。第二步启用并启动服务# 重载 systemd 配置 sudo systemctl daemon-reload # 启用开机自启 sudo systemctl enable ruoyi-admin.service # 启动服务 sudo systemctl start ruoyi-admin.service # 查看状态关键 sudo systemctl status ruoyi-admin.service # 查看实时日志替代 cat msg.log sudo journalctl -u ruoyi-admin.service -f5.3 验证是否生效三招确认 systemd 守护到位检查进程归属ps aux | grep ruoyi-adminUSER列应为ruoyi非rootCMD列应为完整java -Xms...命令模拟崩溃测试sudo kill -9 $(pgrep -f ruoyi-admin.jar)等待 10 秒执行sudo systemctl status ruoyi-admin.service应显示active (running)且Main PID变化日志检索能力sudo journalctl -u ruoyi-admin.service --since 2 hours ago | grep Started能精准查到启动记录证明日志已接入systemd。5.4 避坑常见问题与血泪经验现象systemctl start后状态为failedjournalctl显示Permission denied原因ruoyi用户对ruoyi-admin.jar或application.yml文件无读取权限或WorkingDirectory目录不可访问。解决sudo chown -R ruoyi:ruoyi /home/ruoyi/ruoyi-adminsudo chmod 755 /home/ruoyi/ruoyi-admin确保所有文件属主为ruoyi。现象服务启动成功但http://ip:8080无法访问netstat -tuln | grep 8080无监听原因若依后端application.yml中server.port被注释或设为0随机端口或spring.profiles.active指向的配置文件未正确加载。解决检查ruoyi-admin.jar内BOOT-INF/classes/application.yml确认server.port: 8080未被注释若使用外部配置确保--spring.config.locationfile:/home/ruoyi/ruoyi-admin/config/参数已加入ExecStart。现象systemctl stop后进程仍在ps aux还能看到 Java 进程原因Java 进程未响应SIGTERM可能因线程阻塞或未注册 Shutdown Hook。解决在若依后端Application.java中添加优雅关闭逻辑SpringBootApplication public class RuoyiAdminApplication { public static void main(String[] args) { ConfigurableApplicationContext context SpringApplication.run(RuoyiAdminApplication.class, args); // 注册 JVM 关闭钩子 Runtime.getRuntime().addShutdownHook(new Thread(() - { System.out.println(Shutting down Ruoyi Admin gracefully...); // 此处可关闭线程池、释放资源 })); } }6. 如何 5 分钟内定位部署故障一份可立即执行的排查清单与决策树从第一次部署若依到现在我给自己立下铁律任何部署问题必须在 5 分钟内锁定根因否则立刻执行标准化排查流程。这套流程不是凭空而来是踩过“Nginx 配置漏掉try_files”、“Tomcatweb.xml位置放错”、“publicPath用/而非./”等上百个坑后提炼出的最小可行路径。它不依赖经验直觉只依赖可验证的事实。现在我把这份清单交给你照着做5 分钟出答案。6.1 第一步确定故障类型30 秒打开浏览器开发者工具F12切到 Network 面板刷新页面观察第一个请求通常是index.html的状态码如果是 200前端资源加载成功问题在 JS 执行或后端 API跳到第 3 步如果是 404Nginx/Tomcat 未正确提供index.html问题在服务端静态资源配置跳到第 2 步如果是 502/503Nginx 无法连接后端如proxy_pass地址错误、后端未启动问题在反向代理跳到第 4 步。提示不要看控制台 Console 的 JS 错误那是结果不是原因。先看 Network 的 HTTP 状态码它是真相的源头。6.2 第二步验证静态资源服务90 秒针对 404 故障执行以下命令Linux# 1. 检查 Nginx 配置中 root 路径是否指向 dist 目录 sudo nginx -T 2/dev/null | grep -A 5 location / # 2. 确认 dist 目录存在且有 index.html ls -l /usr/share/nginx/html/index.html # Nginx 路径 # 或 ls -l /home/ruoyi/tomcat/webapps/dist/index.html # Tomcat 路径 # 3. 检查 Nginx 是否监听 80 端口 sudo ss -tuln | grep :80 # 4. 如果是 Tomcat确认 web.xml 是否在正确位置 ls -l /home/ruoyi/tomcat/webapps/dist/WEB-INF/web.xml若root路径错误 → 修改nginx.conf若index.html不存在 → 重新npm run build:prod并复制dist若ss无输出 →sudo systemctl start nginx若web.xml不存在 → 按第 3 章方法重建。6.3 第三步验证前端路由与资源路径120 秒若index.html返回 200但页面白屏或菜单不加载# 1. 查看 index.html 源码确认 script 标签 src 路径 curl -s http://localhost/index.html | grep src\ # 2. 检查该 JS 文件是否能直接访问替换为实际路径 curl -I http://localhost/js/app.xxx.js # 应返回 200 # 3. 检查 Vue Router base 是否匹配 curl -s http://localhost/index.html | grep BASE_URL\|publicPath若src是/js/...但返回 404 →vue.config.js中publicPath必须为./若src是./js/...但返回 404 → Nginxroot路径未指向dist目录或 Tomcatdist未本文还有配套的精品资源点击获取
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表