尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SpringBoot+Vue前后端分离项目部署实战:Nginx反向代理与自动化脚本

SpringBoot+Vue前后端分离项目部署实战:Nginx反向代理与自动化脚本 1. 项目概述从单体到分离的部署跃迁前后端分离架构如今已是现代Web应用开发的标配但很多开发者尤其是从传统单体项目转型过来的朋友常常在“最后一公里”——也就是项目部署上栽跟头。我见过不少团队开发时前端用Vue、React跑得飞起后端SpringBoot接口调试得明明白白可一到要打包上线就手忙脚乱配置冲突、端口占用、跨域问题、静态资源404错误接踵而至。这感觉就像精心组装了一台高性能电脑最后却因为电源线插错了接口而无法开机非常令人沮丧。今天我们就来彻底解决这个问题。我将以一个典型的SpringBoot后端 Vue.js前端的分离项目为例手把手带你走通从本地开发环境到生产服务器部署的全流程。我们不仅会部署更要理解每一步背后的逻辑为什么Nginx要这么配置为什么SpringBoot的application.yml生产环境和开发环境要区分静态资源到底该放在哪里理解了这些“为什么”你就能举一反三应对各种复杂的部署场景无论是用传统的物理服务器、云主机还是容器化的Docker环境。这次实战的目标很明确让你获得一份清晰、可靠、可复现的部署清单下次再部署类似项目时能心中有数一步到位。2. 部署架构设计与核心思路拆解在动手敲命令之前我们必须先厘清部署的总体蓝图。前后端分离部署核心思想就是将前端应用和后端应用作为两个独立的服务来发布它们通过网络请求通常是HTTP/HTTPS进行通信。这与传统单体应用将JSP、Thymeleaf模板和Java代码打包成一个WAR/JAR文件有本质区别。2.1 为什么选择“反向代理”模式最常见的部署架构是“反向代理”模式。在这种模式下用户的所有请求首先到达一个统一的入口——通常是Nginx这类高性能的Web服务器。Nginx扮演了“交通警察”和“内容分发者”的角色。对于前端请求当用户访问https://your-domain.com时Nginx接收到这个请求。因为它配置了规则所有对根路径或特定静态资源路径如/js/,/css/,/img/的请求都会被指向到本地存放的、已经构建好的前端静态文件HTML, CSS, JavaScript。Nginx直接将这些文件返回给用户的浏览器。对于后端API请求当前端页面在浏览器中运行起来后其中的JavaScript代码需要调用后端接口获取数据。这些API请求通常带有特定的路径前缀比如/api/。Nginx配置了另一条规则将所有以/api/开头的请求反向代理到后端的SpringBoot应用实际运行的地址例如http://localhost:8080。这样对前端来说它始终是在向同一个域名发送请求完美避开了跨域问题而对后端来说它感知到的请求来源就是Nginx服务器本身。这种架构的优势非常明显职责清晰、性能优化、便于扩展。前端专注展示由Nginx高效分发静态文件后端专注数据处理可以独立进行水平扩展。即使后端服务地址变更也只需修改Nginx配置前端代码无需改动。2.2 环境与工具选型考量本次实战我们基于最通用的Linux服务器环境如CentOS 7/8或Ubuntu 20.04 LTS进行。工具链的选择遵循“稳定、高效、通用”的原则Web服务器Nginx理由轻量、高性能、高并发处理能力强反向代理和静态资源服务是其看家本领配置相对简单社区资源丰富。备选Apache HTTPD也可以但在处理高并发静态资源和作为反向代理网关时Nginx通常是更优选择。Java运行环境OpenJDK 8/11/17理由SpringBoot 2.x 通常对应JDK 8或11SpringBoot 3.x 则需要JDK 17。选择与你的SpringBoot版本匹配的LTS长期支持版本。OpenJDK是开源首选。操作通过系统包管理器yum或apt安装或从官网下载tar包手动配置JAVA_HOME。项目构建工具Maven 或 Gradle理由在服务器上我们需要一个工具来编译打包SpringBoot项目。虽然可以在本地打包好上传但在服务器上保留构建能力便于后续自动化部署。操作同样通过包管理器安装。版本管理可选但推荐Git理由将代码仓库克隆到服务器便于拉取更新和版本回退。操作安装Git配置项目仓库的SSH密钥或账号密码。前端构建环境Node.js npm理由即使前端静态文件最终是上传的在服务器上保留Node环境也便于调试或执行一些自动化构建脚本。操作建议使用nvm管理Node版本避免权限问题。注意生产环境务必保持最小化安装原则。只安装运行所必需的软件和服务并确保它们都更新到安全稳定版本。不必要的软件会增大系统攻击面。3. 后端SpringBoot应用部署详解后端是数据逻辑的核心它的部署要求是稳定、可监控、易维护。3.1 生产环境配置文件隔离这是至关重要的一步。开发环境的配置如连接本地数据库localhost:3306开启Swagger文档设置logging.level.debug绝对不能用于生产。创建Profile专属配置在SpringBoot项目的src/main/resources目录下我们通常会有application.yml- 主配置存放通用设置。application-dev.yml- 开发环境配置通过spring.profiles.activedev激活。application-prod.yml-生产环境配置这是我们部署的重点。application-prod.yml核心配置示例server: port: 8080 # 后端应用运行端口注意不要与系统其他服务冲突 servlet: context-path: /api # 统一API前缀便于Nginx反向代理规则配置 spring: datasource: url: jdbc:mysql://生产数据库IP:3306/your_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: prod_user # 使用权限受限的数据库用户绝非root password: strong_password # 密码应从环境变量或配置中心获取此处仅为示例 driver-class-name: com.mysql.cj.jdbc.Driver redis: host: 生产RedisIP port: 6379 password: redis_password database: 0 # 生产环境通常关闭Swagger # swagger-ui: # enabled: false # 日志配置生产环境日志级别通常为INFO或WARN日志文件按日期滚动 logging: level: root: info com.yourcompany: debug # 可以保留自己项目包的debug级别以便排查问题 file: name: /var/log/your-springboot-app/app.log # 指定日志路径确保目录有写入权限 logback: rollingpolicy: max-file-size: 50MB max-history: 30关键点数据库、Redis等中间件的连接信息必须改为生产环境的地址和认证信息。useSSLfalse仅在内网可信环境使用公网应考虑启用SSL。打包时激活Profile在服务器上使用Maven打包时指定使用prod配置文件。# 在项目根目录执行 mvn clean package -DskipTests -P prod这个命令会激活prod这个profile从而将application-prod.yml中的配置打包进最终的JAR文件。-DskipTests是为了跳过测试加速打包过程。3.2 打包与传输打包上述Maven命令执行成功后会在target目录下生成一个可执行的JAR文件名称通常为your-app-name-0.0.1-SNAPSHOT.jar。传输到服务器使用scp或sftp工具将JAR包上传到服务器的指定目录例如/opt/app/backend/。scp target/your-app.jar useryour-server-ip:/opt/app/backend/3.3 服务化运行与管理Systemd让SpringBoot应用在后台稳定运行并在服务器重启后能自动启动最好的方式是将其配置为系统服务。创建Systemd服务文件在服务器上创建文件/etc/systemd/system/your-springboot-app.service。[Unit] DescriptionYour SpringBoot Backend Application Afternetwork.target syslog.target [Service] Typesimple Userappuser # 建议创建一个非root的专用用户来运行应用提升安全性 WorkingDirectory/opt/app/backend ExecStart/usr/bin/java -Xms512m -Xmx1024m -jar your-app.jar --spring.profiles.activeprod ExecStop/bin/kill -15 $MAINPID Restartalways RestartSec10 StandardOutputjournal StandardErrorjournal [Install] WantedBymulti-user.target关键参数解释Userappuser使用非root用户运行是重要的安全实践。需要提前创建该用户并赋予相关目录的权限。-Xms512m -Xmx1024m设置JVM堆内存的初始值和最大值。根据你的应用实际内存占用调整。--spring.profiles.activeprod显式指定激活生产环境配置这是一个双保险。Restartalways当服务异常退出时自动重启。WorkingDirectory设置工作目录这样应用生成的临时文件或日志都会在这个目录下。启动并启用服务sudo systemctl daemon-reload # 重新加载systemd配置 sudo systemctl start your-springboot-app.service # 启动服务 sudo systemctl enable your-springboot-app.service # 设置开机自启 sudo systemctl status your-springboot-app.service # 检查服务状态查看日志# 使用journalctl查看systemd管理的日志 sudo journalctl -u your-springboot-app.service -f # 或者直接查看我们配置的日志文件 tail -f /var/log/your-springboot-app/app.log此时后端应用应该已经在8080端口运行。你可以先在服务器本地用curl http://localhost:8080/api/health假设你有健康检查接口测试一下。4. 前端Vue.js应用部署详解前端部署的核心是将源代码“构建”成纯粹的静态文件HTML, CSS, JS, 图片等然后交给Nginx来托管。4.1 生产环境构建与配置环境变量配置前端需要知道后端API的地址。通常通过环境变量注入。在Vue项目根目录创建或修改.env.production文件NODE_ENVproduction VUE_APP_API_BASE_URL/api # 关键这里不是写服务器IP而是写Nginx代理的路径前缀为什么是/api因为我们在Nginx中配置了所有/api的请求都会被转发到后端的8080端口。这样前端代码中axios的baseURL设置为这个变量后所有API请求都会发向同域下的/api路径由Nginx处理代理完美解决跨域。执行生产构建在项目根目录运行构建命令。npm run build对于Vue CLI创建的项目这个命令会在项目下生成一个dist目录里面就是构建好的静态资源。检查构建产物确保dist/index.html文件存在并且其中的JS、CSS文件引用路径是正确的通常是相对路径./或/。4.2 静态资源上传与Nginx配置上传静态资源将整个dist目录下的内容上传到服务器上Nginx用来存放静态文件的目录例如/usr/share/nginx/html/your-frontend-app/。scp -r dist/* useryour-server-ip:/usr/share/nginx/html/your-frontend-app/配置Nginx这是前后端联调的关键。编辑Nginx的主配置文件通常在/etc/nginx/nginx.conf或在其/etc/nginx/conf.d/目录下创建一个新的配置文件如your-app.conf。server { listen 80; # 监听80端口HTTP server_name your-domain.com www.your-domain.com; # 你的域名如果没有域名就用服务器IP # 前端静态资源服务 location / { root /usr/share/nginx/html/your-frontend-app; # 前端文件存放目录 index index.html index.htm; try_files $uri $uri/ /index.html; # 支持Vue Router的history模式 } # 后端API反向代理 location /api/ { proxy_pass http://localhost:8080/api/; # 代理到后端SpringBoot应用 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_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; } # 可选静态资源缓存优化提升性能 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control public, immutable; } }try_files指令这是支持Vue Router的history模式的关键。当用户直接访问一个前端路由如/dashboard时Nginx会尝试查找对应的文件找不到则返回index.html由前端路由接管。proxy_pass指令将所有以/api/开头的请求原样转发到http://localhost:8080并且路径中的/api/也会传递给后端。后端应用设置的server.servlet.context-path/api正好与之匹配。proxy_set_header这些头部信息将真实的客户端IP等信息传递给后端应用否则后端日志里看到的客户端IP都是Nginx服务器的IP127.0.0.1。测试Nginx配置并重载sudo nginx -t # 测试配置文件语法是否正确 sudo systemctl reload nginx # 重载Nginx配置使新配置生效如果一切顺利现在访问你的服务器IP或域名应该能看到前端页面并且页面发起的API请求也能正常获取数据。5. 部署全流程串联与自动化脚本将以上步骤串联起来就是一个完整的手动部署流程。但对于频繁的迭代更新手动操作效率低下且易出错。我们可以编写一个简单的Shell脚本来自动化这个过程。5.1 示例部署脚本 (deploy.sh)这个脚本假设代码已在服务器上通过Git管理并部署在/opt/app目录下。#!/bin/bash # 部署脚本 set -e # 遇到错误立即退出 APP_NAMEyour-springboot-app FRONTEND_NAMEyour-frontend-app BACKEND_DIR/opt/app/backend FRONTEND_DIR/opt/app/frontend NGINX_HTML_DIR/usr/share/nginx/html echo 开始部署 $APP_NAME # 1. 拉取最新代码 echo 1. 拉取后端最新代码... cd $BACKEND_DIR git pull origin main echo 2. 拉取前端最新代码... cd $FRONTEND_DIR git pull origin main # 2. 构建后端 echo 3. 构建SpringBoot后端应用... cd $BACKEND_DIR mvn clean package -DskipTests -P prod # 备份旧JAR包可选 cp -f target/*.jar app.jar.bak # 找到最新的JAR包并复制为统一名称方便服务文件调用 NEW_JAR$(ls target/*.jar | head -n 1) cp -f $NEW_JAR app.jar # 3. 构建前端 echo 4. 构建Vue.js前端应用... cd $FRONTEND_DIR npm install # 如果依赖有变化 npm run build # 4. 重启后端服务 echo 5. 重启后端SpringBoot服务... sudo systemctl restart $APP_NAME.service echo 等待10秒应用启动... sleep 10 sudo systemctl status $APP_NAME.service --no-pager # 5. 更新前端静态文件 echo 6. 更新前端静态文件... sudo rm -rf $NGINX_HTML_DIR/$FRONTEND_NAME/* sudo cp -r $FRONTEND_DIR/dist/* $NGINX_HTML_DIR/$FRONTEND_NAME/ sudo chown -R nginx:nginx $NGINX_HTML_DIR/$FRONTEND_NAME # 确保Nginx用户有权限读取 # 6. 重载Nginx echo 7. 重载Nginx配置... sudo nginx -t sudo systemctl reload nginx echo 部署完成 使用前注意事项给脚本执行权限chmod x deploy.sh。根据你的实际目录结构、服务名、构建命令进行修改。首次运行前确保backend和frontend目录已通过git clone初始化。npm install这步比较耗时如果依赖稳定可以在判断package-lock.json有变化时才执行。5.2 进阶考量使用Docker容器化部署对于更复杂的环境或追求更高一致性的团队容器化是必然选择。你可以为后端和前端的Nginx分别编写Dockerfile然后使用docker-compose.yml编排。后端Dockerfile示例FROM openjdk:11-jre-slim VOLUME /tmp COPY target/*.jar app.jar ENTRYPOINT [java,-jar,/app.jar,--spring.profiles.activeprod]前端Nginx Dockerfile示例FROM nginx:alpine COPY dist/ /usr/share/nginx/html/ COPY nginx.conf /etc/nginx/conf.d/default.confdocker-compose.yml示例version: 3.8 services: backend: build: ./backend container_name: springboot-app ports: - 8080:8080 environment: - SPRING_PROFILES_ACTIVEprod networks: - app-network frontend: build: ./frontend container_name: vue-app ports: - 80:80 depends_on: - backend networks: - app-network networks: app-network: driver: bridge这种方式将环境依赖完全打包在任何安装了Docker的机器上都能获得一致的运行效果是持续集成/持续部署CI/CD的基石。6. 部署后验证、监控与常见问题排查部署完成不是终点确保应用稳定运行并建立监控反馈机制同样重要。6.1 部署验证清单完成部署后按照以下清单逐一检查网络连通性服务器防火墙是否开放了80HTTP、443HTTPS如果配置了SSL端口sudo firewall-cmd --list-ports # CentOS sudo ufw status verbose # Ubuntu服务状态后端SpringBoot服务和Nginx服务是否都处于active (running)状态sudo systemctl status nginx sudo systemctl status your-springboot-app.service端口监听应用是否在预期的端口上监听sudo netstat -tlnp | grep -E (80|8080|443)前端访问浏览器访问服务器IP或域名页面是否能正常加载无JS错误。API接口测试打开浏览器开发者工具F12的“网络(Network)”选项卡刷新页面查看对/api/的请求是否成功状态码200或业务预期码。日志检查查看后端应用日志和Nginx错误日志(/var/log/nginx/error.log)是否有任何ERROR或WARN级别的异常信息。6.2 常见问题与排查技巧即使按照步骤操作也可能会遇到问题。这里记录几个我踩过的“坑”问题一前端页面空白控制台报错404或Failed to load resource排查检查Nginx的root指令路径是否正确前端文件是否成功上传到了该目录。检查try_files指令是否配置。对于Vue Router的history模式try_files $uri $uri/ /index.html;是必须的。技巧直接在服务器上curl http://localhost/your-app-path/看Nginx返回的是前端HTML还是404页面。问题二前端页面能打开但所有API请求都报404或500错误排查检查Nginx配置中location /api/的proxy_pass地址是否正确后端服务是否在运行curl http://localhost:8080/api/health。检查后端SpringBoot的server.servlet.context-path是否与Nginx代理的路径匹配都应该是/api。查看Nginx的access.log和error.log看请求是否被转发转发地址是什么。技巧在Nginx的location /api/块中添加一行add_header X-Debug-Proxy-Pass $proxy_host;然后在浏览器响应头里查看这个自定义头确认请求被转发到了哪里。问题三API请求返回403 Forbidden或CORS跨域错误排查这通常发生在你误将前端开发时的代理配置如vue.config.js中的proxy带到了生产构建中或者Nginx代理配置不正确导致请求没有经过Nginx代理而是直接从前端浏览器发往后端IP触发了浏览器的同源策略。解决确保前端生产环境配置.env.production中的API地址是相对路径/api而不是绝对URL。确保Nginx配置正确。问题四静态资源JS/CSS加载失败报MIME type错误排查Nginx可能没有正确识别文件类型。检查Nginx配置中是否包含了默认的MIME类型文件mime.types通常在主配置中通过include /etc/nginx/mime.types;引入。解决确保Nginx配置文件中存在这行引入。问题五上传文件大小限制现象前端上传大文件失败。解决需要在SpringBoot和Nginx两端同时调整。SpringBoot在application-prod.yml中设置spring.servlet.multipart.max-file-size和max-request-size。Nginx在server或location块中设置client_max_body_size 100M;例如调整为100M。6.3 简单的监控与维护日志轮转使用Linux自带的logrotate工具定期压缩和清理应用日志和Nginx日志防止磁盘被撑满。可以配置/etc/logrotate.d/下的自定义规则。进程监控使用systemctl status定期检查服务状态。也可以使用更高级的监控工具如PrometheusGrafana配合Spring Boot Actuator暴露的指标进行可视化监控。备份定期备份数据库、应用程序配置文件以及构建好的JAR包和前端dist目录。部署是一个系统工程涉及开发、运维多个环节的协作。最好的实践是将上述流程文档化、脚本化并融入到团队的CI/CD流水线中。每一次部署都应该是可预测、可重复的。当你熟悉了这套流程后无论是部署到单台服务器还是扩展到负载均衡集群其核心思想都是相通的。希望这份详尽的实战指南能成为你下次部署时的可靠参考。
返回列表