若依前后端分离部署全攻略:Linux+Nginx与Windows+Tomcat实战指南
简介:若依框架是一套全面开源的快速开发平台,前端采用Vue和Element UI,后端基于Spring Boot、Security、Redis与Jwt。这份部署文档面向需要在Linux或Windows环境中独立完成若依前后端分离项目上线的开发者,覆盖从代码打包、代理配置到服务启动的完整流程。文档重点讲解两大典型场景:一是Linux加Nginx部署,涉及后台Jar包生成、前端Dist构建、Redis与Nginx安装配置以及Nohup后台启动;二是Windows加Tomcat部署,包括POM改War、Webapps目录整理、Service配置和刷新404问题的修复。同时针对调用第三方API时的跨域困境,提供后端CORS、前端Proxy及Nginx反向代理三种应对思路。资源为一份Docx文档,压缩包约223KB,结构紧凑可直接按步骤操作。已有7764人学习浏览,适合具备Spring Boot和Vue基础、希望快速落地若依项目的初中级开发者,尤其能避免菜单空白、打包后失效等常见坑。
1. 部署若依前后端分离:先定 Linux+Nginx 还是 Windows+Tomcat
接手若依(RuoYi)前后端分离项目部署,我遇到最多的问题不是代码写不出来,而是环境方案没定清楚就盲目开跑。若依作为一套全部开源、个人和企业都能免费使用的快速开发平台,前端用 Vue + Element UI,后端用 Spring Boot + Spring Security + Redis + Jwt,这套组合在真实项目里出现频率极高。但很多开发者在自己的 Windows 开发机上跑得通,一上服务器就各种 404、空白页、菜单打不开,本质上是没分清两套部署路径:Linux 服务器上用 Nginx 做反向代理,和 Windows 服务器上用 Tomcat 直接扛。这两套方案从打包方式到配置项完全不同,我建议接到部署任务先回答一个问题:手头服务器装的是 Linux 还是 Windows?没有 Nginx 的话后端接口怎么暴露?方案定死,后面每一步才有意义。
2. 打包后台 jar 和前端 dist:装环境之前最容易翻车的两步
2.1 后台打包:IDEA Terminal 里的 mvn clean package
若依后端打包几乎没有第二种选择,就是 Maven 打 jar 包。我一般在 IDEA 自带的 Terminal 窗口里执行:
mvn clean package -DskipTests执行完去项目根目录下的target文件夹里找*.jar文件,那个就是后端产物。-DskipTests的意思是跳过单元测试,因为我遇到过测试类里连不上测试库导致打包中断的情况,既然目标只是部署,先跳过去再说。
这里有个细节容易被忽略:target目录里通常会有两个 jar,一个原始 jar(带-original后缀或用.original结尾),一个是 Spring Boot 可执行 jar。部署要认准不带original的那个,否则启动就会报「没有主清单属性」。判断也很简单,可执行 jar 一般有 60MB 以上,原始 jar 通常只有几百 KB。复制到服务器之前,我习惯先本地java -jar跑一遍看端口能不能起,这一步能在开发机上暴露数据库配置和 Redis 连接问题,省得到服务器上再排查。
2.2 前端打包:npm run build:prod 与 dist 目录
若依前端的打包命令基本固定,在ruoyi-ui目录(也就是前端工程根目录)下执行:
npm run build:prod --report--report参数会在打包完成后生成一份依赖分析报告report.html,主要用来定位打包体积过大问题,不需要报告的时候去掉也不影响 dist 生成。打包完成会多出一个dist目录,里面是index.html、static目录和一堆编译后的 js/css。整个dist目录就是前端静态资源的全部内容,后续复制到服务器上,动的就是这一个文件夹。
前端打包对 Node.js 版本有要求,若依这类 Vue 2 项目建议 Node 14 或 16 LTS,太新的 Node 版本可能在node-sass编译阶段直接报错。如果npm run build:prod报 Python 或 binding 相关错误,常见做法是删掉node_modules和package-lock.json,换 Node 版本后重新npm install,这比单修依赖快得多。另外,打包前要看一眼vue.config.js里的publicPath,这个配置直接决定了 dist 里index.html引用静态资源时前缀对不对,后面第三章还会专门讲它的坑。
2.3 环境变量检查清单:复制部署包前先过一遍
打包动作本身不难,难的是打包前把运行参数对清楚。我一般先在本地确认几件事:后端application.yml里的数据库地址、账号、密码有没有指向正式库。若依默认配置里带了本地 MySQL 连接信息和 Redis 密码项,如果服务器上 Redis 没配密码而代码里写死了密码,启动时会一直报连接超时。前端.env.production里的VUE_APP_BASE_API也很重要,它决定了生产环境请求后端接口用的路径前缀,Linux + Nginx 方案里通常保持/prod-api,Windows + Tomcat 方案里要改成实际部署的上下文路径。
有一回我帮一个项目团队排查问题,前端都部署上去了,登录时报「网络异常」,最后发现就是.env.production里把VUE_APP_BASE_API写成了开发环境的http://localhost:8080,浏览器访问服务器的页面,请求却打回开发者本机,自然必挂无疑。这类问题不在第 2 章爆发,就一定在第 6 章验证时爆发,建议打包前花五分钟把这张环境清单过一遍。
3. Linux + Nginx 部署:Redis、Nginx 配置与后台启停
3.1 安装 Redis 并确认缓存连通
若依后端的登录验证码、用户 token 都依赖 Redis,服务器上没跑 Redis 的话,后端服务能启动但登录会一直卡在验证码错误。Linux 下装 Redis 我通常直接走系统源:
yum install -y redis systemctl enable redis systemctl start redisUbuntu 系对应把yum换成apt-get install -y redis-server。装好后下一步不是急着启动后端,而是先确认 Redis 能存能取。用redis-cli敲一个 ping,还做不到的,检查bind和protected-mode:若依后端和 Redis 在同一台机器上时,redis.conf里保持默认只监听127.0.0.1即可,后端连接地址填127.0.0.1:6379就行;如果 Redis 在其他机器,bind要改成内网 IP,protected-mode要设 no,否则代码里连接 Redis 会被拒。
3.2 安装 Nginx 并修改 conf/nginx.conf
Nginx 在若依这套架构里承担两件事:托管前端 dist 静态文件,以及把/prod-api/开头的接口请求反向代理到后端 jar 进程。CentOS 上安装:
yum install -y nginx nginx装完以后修改conf/nginx.conf,这是整套部署的核心配置:
server { listen 80; server_name _; # 前端静态资源 location / { root /home/ruoyi/dist; index index.html; try_files $uri $uri/ /index.html; } # 后端接口反向代理 location /prod-api/ { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://127.0.0.1:8080/prod-api/; } }location /里的 root 指向你上传 dist 的绝对路径,try_files这行是配给 Vue 路由用的,刷新页面时让它回退到index.html。location /prod-api/这一段把前端请求转发到后端 8080 端口,注意proxy_pass结尾带着/prod-api/,这样前端/prod-api/login经过代理后完整映射到后端接口路径,后端不需要额外处理前缀。若后端 jar 改了端口或部署路径,只需同步改proxy_pass这一个位置。改完用nginx -t验证语法,再nginx -s reload重载,这一步别省。
3.3 启动 jar 包保活,日志重定向别写错
后端 jar 的启动命令就是那经典的一行:
nohup java -jar ruoyi-admin.jar > msg.log 2>&1 &nohup让它忽略挂断信号,&让它在后台运行,> msg.log 2>&1把标准输出和错误输出都写进当前目录下的msg.log。这样做的直接好处是:关掉终端窗口服务不会被杀,一旦启动失败还能打开 msg.log 看真实报错。如果是帮别人维护的机器,我会再加一层ulimit -n 65535提高文件句柄上限,避免高并发下出现 too many open files。
启动后等十秒左右先看进程还在不在:
ps -ef | grep java tail -f msg.log日志里看到Started RuoYiApplication这类字样,说明后端已起来。再确认 8080 端口在监听:ss -lntp | grep 8080。全套起来后,浏览器输入服务器 IP 就能看到若依登录页,默认账号admin/admin123进入系统。这里提一下很多人踩过的坑:后期在系统里改了菜单或调整了前端代码后重新打包部署,发现登录正常但菜单打不开,多半是vue.config.js的配置被改动了。若依默认生成的配置里,publicPath可能是类似./的写法,部署阶段要按实际情况调整,把/之前的.去掉,再重新打包上传 dist。这行配置改动虽小,影响的是打包后 index.html 里所有静态资源的前缀拼接,前缀错了浏览器就找不到 js/css,表现就是菜单点击无响应或页面空白。
另外,jar 启动失败时,日志里最常出现的几个原因:8080端口被占用,改端口或先杀掉占用进程;redis.clients.jedis.exceptions.JedisConnectionException连不上 Redis,回 3.1 检查;MySQL 连接串写错导致Communications link failure。msg.log 是整套若依部署里最直接的黑匣子,任何页面异常都要先回来翻它。
4. Windows + Tomcat 部署:war 包、service.xml 与刷新 404
4.1 修改 pom.xml,从 jar 切换到 war
没有 Nginx、需要在 Windows 上用 Tomcat 跑时,后端打包方式要换。打开后端根目录的pom.xml,找到打包类型配置:
<groupId>com.ruoyi</groupId> <artifactId>ruoyi-admin</artifactId> <version>xxx</version> <packaging>war</packaging>关键就是<packaging>从jar改成war。改完后同样在 Terminal 里执行:
mvn clean package -DskipTests这次target目录里生成的是ruoyi-admin.war。打包出的 war 复制到 Tomcat 的webapps目录下,重命名为prod-api,这样 war 解压后访问路径就是http://ip:端口/prod-api,与前端请求的后端前缀保持一致。这一步懒得起别名也行,但后面改service.xml和前端代理时都要在路径上多绕一层,我建议还是按prod-api命名。
4.2 复制 dist 到 webapps 并改 service.xml
前端部分把dist整个目录复制到 Tomcat 的webapps目录下,可以和prod-api并列放着。为了让 Tomcat 启动时直接把项目根路径映射到 dist 内容,需要打开 Tomcatconf目录下的service.xml(文档里写成 service.xml,实际上 Tomcat 安装目录里真实文件是server.xml,这两个名字我都见过被混用,以conf/server.xml为准)。在<Host>节点内部加上:
<Context path="/" docBase="D:/apache-tomcat/webapps/dist" reloadable="true" crossContext="true"></Context>docBase可以填 dist 的绝对路径,也可以填相对于 webapps 的路径。path="/"表示访问根路径时直接加载 dist。这一步不加的话,登录页能打开,但登录之后画面就空白了——因为本地开发时访问路径是ip:端口/router这一类带路由的地址,Tomcat 默认的 Context 映射不处理这种前端路由回退,加了这个 Context 等于给前端路由修了一条直达通道。
server.xml里还要检查 Tomcat 自身的启动端口,默认8080,如果和平时的后端端口撞了,调<Connector port="8080"那一行的端口值。改完server.xml必须重启 Tomcat 才生效,只重启应用没用。
4.3 Tomcat 方案刷新 404:新建 WEB-INF/web.xml 兜底
Tomcat 下部署若依还有一个高频问题:登录进系统后正常操作没问题,但鼠标点到刷新浏览器按钮,十有八九会跳到 404。原因很简单:Vue 是单页应用,路由切换都在前端内部完成,刷新时浏览器按当前 URL 去请求 Tomcat,Tomcat 找不到对应的物理文件,自然返回 404。
解决方案是在 dist 目录下新建WEB-INF文件夹,在里面放一个web.xml,把 404 错误页指回前端首页:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1" metadata-complete="true"> <display-name>Router for Tomcat</display-name> <error-page> <error-code>404</error-code> <location>/index.html</location> </error-page> </web-app>这段配置的逻辑是:所有 404 响应统一重定向到index.html,由前端路由自己接管 URL 判断。version="3.1"对应 Tomcat 8.5/9,如果你的 Tomcat 版本较老,把 web-app 版本降到 3.0 也一样能用。新建完这个文件,重启 Tomcat,再刷新页面就不会 404 了。
整体走完这套 Windows + Tomcat 方案,访问关系是:浏览器请求 Tomcat8080端口,根路径/由 Context 映射加载 dist 内容,/prod-api下的接口请求走到解压后的 war 应用里。没有 Nginx 承担静态托管和代理,Tomcat 一个人把两件事都干了。
5. 跨域与排查:第三方 API 无法调用时的三处配置
5.1 先定位跨域发生在哪一层
若依项目里被问到最多的跨域问题,是前端页面需要调用第三方开放 API,比如地图服务这类外部接口。浏览器控制台报熟悉的No 'Access-Control-Allow-Origin' header is present,往往先要分清是后端接口跨域,还是第三方 API 跨域。如果是若依前后端之间跨域,开发时靠 devServer 代理,部署后靠 Nginx 同源转发,通常不会暴露;而直接在前端代码里axios.get打第三方 API,只要第三方没给你开 CORS 头,浏览器直接拦截,这就是另一套思路了。
解决办法有三个层级,按项目实际情况选一个:最省事的是让后端转发,即前端请求自家后端接口,后端用 HTTP 客户端去请求第三方 API,浏览器全程只和同源后端通信;其次是在 Nginx 上做一个专门的转发 location,相当于半个网关;最后才是依赖第三方主动开放 CORS 头,这个多数情况下指望不上。
5.2 后端 CORS 配置与 Nginx 转发
如果后端要直接承接跨域请求,在 Spring Boot 里加一个全局 CORS 配置类:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .maxAge(3600); } }allowedOriginPatterns比allowedOrigins更宽松,允许带凭证的跨域请求,生产环境建议缩到具体的域名而不是直接*。这个方法只对若依后端接口生效,不会影响第三方 API。
对于第三方 API,我一般优先在 Nginx 上加转发配置:
location /third-api/ { proxy_pass https://外部API域名/; proxy_set_header Host 外部API域名; }这样前端代码里把请求地址从https://外部域名/xxx改成/third-api/xxx,请求到了自家服务器后由 Nginx 转发,浏览器和第三方之间不再直接通信,跨域问题从根上消失。前端.env.production里把VUE_APP_BASE_API对应的公共接口前缀设置好即可。
5.3 部署避坑:菜单打不开、空白页、内存不足
记录几条真实项目中重复出现的问题,每一条都是「现象 → 原因 → 解决」的结构:
现象一:登录页正常,登录后菜单点了没反应。原因出在vue.config.js的publicPath配置不当,打包后的 JS/CSS 资源路径带前缀,浏览器加载不到资源但页面骨架还在。解决方法是把publicPath调整成部署环境可访问的路径,重新打包上传 dist,并清一下浏览器缓存或换无痕窗口验证。
现象二:Windows + Tomcat 部署,登录成功但跳转后空白页。原因是 Tomcat 没有把根路径映射到 dist,前端路由地址在 Tomcat 上找不到对应应用,如 4.2 所说在server.xml的<Host>下加<Context>配置即可。有人会试图改成 hash 路由来绕,但我建议还是修服务器配置,保持 history 路由的 URL 干净。
现象三:页面刷新 404。常见于 Linux 的 Nginx 方案里漏了try_files,以及 Tomcat 方案里漏了WEB-INF/web.xml的 404 错误页兜底。这两处都是为了把「文件不存在」交给前端路由处理,本质是同一件事。
现象四:jar 启动几秒后进程消失,msg.log 提示内存不足或端口冲突。内存不足时给 JVM 显式设置堆大小,例如java -Xms256m -Xmx512m -jar;端口冲突时换端口或者netstat -lntp找出占用进程。
现象五:登录页验证码图片加载不出来。后端日志里能看到连不上 Redis 的异常,验证码是存 Redis 的,Redis 起不来或者 Spring 配置的连接信息对着空地址时,验证码功能就报废。常见做法是redis-cli ping先自证 Redis 存活,再看后端application.yml里 Redis 密码是否与服务器一致。
6. 验证跑通:登录、接口与缓存三件事逐一确认
部署完成不是页面能打开就算完,我每次部署若依至少走一遍完整验证链路。第一步,浏览器输入服务器 IP(或 Tomcat 方案下IP:端口),能看到若依登录页且验证码图片正常加载;第二步,用admin / admin123登录系统,正常进入首页,左侧菜单按权限动态渲染;第三步,随便点开一个菜单,比如用户管理,页面列表有数据且操作按钮响应正常。这三步看着基础,但任何一个环节断裂,后面交到使用者手上就是事故。
推荐再往后端加一层接口验证。打开浏览器开发者工具的 Network 面板,看登录接口/prod-api/login返回的 JSON 里是否带token字段;用curl直接打接口也行:
curl http://127.0.0.1:8080/prod-api/login -X POST -H "Content-Type: application/json" -d '{"username":"admin","password":"admin123"}'返回码 200 且响应里出现token字段,说明后端逻辑和数据库连接都通了。另一件事是验证 Redis 缓存真的在工作:登录一个账号后,在服务器上用redis-cli执行keys *,能看到若依缓存的 token 或验证码相关 key;没有的话,多半是后端 Redis 配置没生效或连错了库。
Linux 方案下还要顺带验证静态资源是否由 Nginx 正常托管:在浏览器里直接访问http://IP/static/js/xxx.js这类路径,能下载文件说明 root 配置正确;访问一个不存在的路由路径,能回退到前端首页而不是 Nginx 404,说明try_files生效。之后我再遇到菜单打不开或页面空白这类问题,第一反应就是带着这几个验证步骤倒查:先curl接口,再tail日志,再看 Nginx 转发方向,问题基本都能定位到某一层。这套验证习惯已经帮我在部署若依时少走了很多弯路,希望也能帮到你。
本文还有配套的精品资源,点击获取