ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

前后台分离项目打包部署实战:Vue+Spring Boot+Nginx+Docker 完整指南

前后台分离项目打包部署实战:Vue+Spring Boot+Nginx+Docker 完整指南 前后台分离项目代码写得再漂亮最后一步打包部署要是掉了链子前面所有功夫全白费。尤其是前后台分离这套架构前端、后端各自独立构建、独立部署中间还夹着一个反向代理层任何一个环节配置对不上线上就是一片白屏加一串 502。这篇文章我把整个“前后台分离打包部署项目”从思路到落地完整拆一遍覆盖前端 Vue 打包、后端 Spring Boot 构建、Nginx 路由与缓存配置、Docker 容器化编排这些核心环节也会把我实际操作中踩过的坑一次说清楚。适合正在做前后台分离项目、准备把项目从本地环境迁到测试服务器或生产环境的人参考后端是 Java Spring Boot、前端是 Vue 系的场景可以直接照搬思路其他技术栈也能借方法论。这里先说明白“前后台分离”在部署层面到底意味着什么。开发环境下前端跑在 Node 热更新服务器上后端跑在 Tomcat 内嵌端口上两者通过代理各干各的很爽。但生产环境根本没有 Node 进程也没有 IDE所有代码都必须被打成静态文件和可执行程序再由 Web 服务器和进程管理器把它们拉起来。这个从“开发态”到“生产态”的转换就是打包和部署的核心价值。所以与其说这是一个部署教程不如说是一次完整的架构落地梳理。1. 前后台分离部署的整体思路与方案选型1.1 前后台分离架构下部署的真正难点前后台分离部署难的不是“打包”这个动作而是“打包完之后怎么让它们协作”。开发时前端代理到后端的地址是 localhost:8080后端连的数据库是本地 root 密码CORS 全放开无所谓。但到了服务器上前端静态文件要有人托管后端进程要常驻且崩溃自动拉起接口域名不能写死数据库密码不能裸奔跨域要么关掉走代理、要么精确配置。这背后是一整套部署规范的建立。另外前后台分离还带来了资源组织方式的变化。前端构建产物是一堆带 hash 的 JS/CSS 文件和 index.html后端产物则是一个可执行 jar 包或 war 包。两者生命周期不同、更新频率不同、回滚策略不同必须分开管理。很多人第一次部署时图省事把前端打包好的 dist 直接塞进后端项目的 resources 目录一起发布这种做法在小 demo 里能跑但到了真实项目里前端改一行文案后端就得重新构建发版非常痛苦。所以从一开始就要明确前端产物归前端后端产物归后端中间用 Nginx 或 CDN 衔接。1.2 一套能落地的部署架构长什么样一套经得起生产环境考验的前后台分离部署架构至少包含这几个角色前端静态资源服务器Nginx、后端应用服务Spring Boot 内嵌 Tomcat、反向代理层同样是 Nginx可以跟前端静态资源服务器合并、数据库与中间件MySQL、Redis、以及可选的容器化编排层Docker Compose 或 K8s。我实际项目中常用的是“Nginx 双职责”方案同一个 Nginx 实例既托管前端静态文件又把 /api 和 /prod-api 这类前缀的请求反向代理到后端服务。这样浏览器永远只跟同一个域名打交道不存在跨域问题Cookie 也能顺畅携带同时运维只需要维护一个入口。如果你有独立域名和 HTTPS 证书这个方案尤其舒服证书只需要配一层。架构确定之后打包部署就变成了三个标准化步骤前端构建、后端构建、配置 Nginx 并启动。下面我从环境准备讲起逐步把每一步的操作细节和参数选择逻辑讲透。2. 环境准备与项目结构调整2.1 服务器端要准备哪些基础环境不管项目多简单服务器上这几样东西必须齐JDK版本与后端项目一致比如 Java 8 或 Java 17、Nginx、Git用于拉取代码、Docker 与 Docker Compose如果走容器化。数据库和 Redis 可以装在宿主机也可以用 Docker 起生产环境我建议独立安装或用云数据库避免容器重启导致数据丢失。环境版本这里有个常见坑服务器上 JDK 版本与本地开发版本不一致明明本地打包运行都正常放到服务器上 jar 包启动直接报 UnsupportedClassVersionError。这是 JDK 主版本号不匹配导致的比如本地用 JDK 17 编译的 class 文件扔到 JDK 8 的运行时里必然跑不起来。所以条件允许时尽量让本地构建机的 JDK 与服务器运行时 JDK 保持同一大版本。Nginx 编译安装和 yum/apt 安装都行但注意 Nginx 版本不要太老至少 1.18 以上对 HTTP/2、gzip 静态压缩的支持更完善。安装完先用 nginx -v 确认版本再检查配置文件语法 nginx -t避免后面写配置时基础环境出问题。2.2 前端项目的打包前配置调整前端项目里最影响打包结果的就是publicPath、路由模式、接口请求地址这几个配置。Vue CLI 项目在vue.config.js里通过publicPath控制静态资源的引用基础路径Vite 项目则是base配置。很多人的前端打包后白屏就是publicPath写错了。如果你的站点部署在域名根路径下publicPath可以配成/如果要部署在http://域名/xxx/这样的子路径下就得设成/xxx/。否则页面加载时 index.html 引用 JS 和 CSS 的路径全部对不上自然白屏。路由模式这块如果用了 Vite 或 Vue Router 的 HTML5 History 模式createWebHistory打包部署后访问非首页路径刷新会 404因为服务器上根本不存在那个路径对应的物理文件。这个问题必须通过 Nginx 的 try_files 配置做回退后面我会给出完整的 Nginx 配置片段。如果你不想处理这个问题可以把路由模式改成 Hash 模式createWebHashHistoryURL 会多一个 # 号但部署上省心很多。接口地址的配置要单独拎出来说。我见过太多项目把接口请求地址写死在代码里比如axios.defaults.baseURL http://localhost:8080/api本地开发没问题一打包到服务器所有请求全打到本地回环地址上直接废掉。正确处理方式是区分环境生产环境走相对路径/api由 Nginx 把/api反向代理到后端真实地址。这样前端产物里不包含任何服务器 IP 或域名迁移环境时不用重新打包。2.3 后端项目的打包前配置调整后端项目打包前最需要关注的是配置文件里的环境相关项。Spring Boot 项目通常有application.yml、application-dev.yml、application-prod.yml打包前要确认spring.profiles.active设置成了生产环境。如果你有多套环境强烈建议用 Maven profile 结合 Spring Boot profile 做联动打包时通过-Pprod参数指定。数据源信息、Redis 地址这些敏感配置生产环境不要硬编码在源码里。常见做法是把配置外置比如 jar 包同级的config/目录下放置application-prod.yml或者通过启动参数--spring.config.locationfile:/path/to/config/指定外部配置。Spring Boot 的应用优先级中外部配置文件优先级高于 jar 包内部的配置文件所以你不用重新打包就能修改生产环境配置这非常实用。我的习惯是 jar 包里只放开发环境的默认配置生产环境配置全部外置这样打包一次可以部署到多台服务器每台只需改自己的配置即可。3. 前端打包实操从 Vue 项目到 Nginx 可托管的静态资源3.1 生产构建与开发构建的差异开发时npm run dev启动的是开发服务器带热更新、带源码映射构建速度慢但调试方便。生产环境要的是npm run build这个命令会做代码压缩、tree shaking、资源指纹hash等优化输出到一个 dist 目录。Vue CLI 默认输出到项目根目录的dist文件夹Vite 默认输出到项目根目录的dist文件夹。构建命令跑完先别急着上传先做三件事检查 dist 目录结构是否完整index.html、static 或 assets 目录、favicon 等、打开本地预览确认页面渲染正常可以用npx serve dist起一个本地静态服务、检查控制台有没有资源加载 404 或接口请求报错。很多人这一步跳过直接把 dist 丢到服务器上结果白屏了也分不清是前端资源路径问题还是后端接口问题。3.2 前端构建命令的常见选择与参数如果你用的是 npm那么生产构建命令一般是npm run build但二次封装时可以加参数。Vite 项目构建时可以指定--outDir控制输出目录也可以通过环境变量VITE_APP_ENVproduction vite build让项目代码读取不同的环境变量文件。构建阶段还需要留意依赖安装的问题。npm install与npm ci是有区别的npm install会根据 package.json 的语义化版本范围安装依赖可能装到新版本npm ci严格按照 package-lock.json 锁定文件安装保证构建环境的一致性。生产环境建议使用npm ci并且把node_modules目录彻底删掉再装避免本地残留的依赖影响构建结果。如果项目里有原生模块或者依赖了特定平台的二进制文件构建机与服务器的操作系统不一致也可能引发问题尽量保证构建环境纯净。3.3 打包后布局异常之类的问题怎么排查热词里“vue 打包后布局异常”是个高频问题。这类问题通常集中在几个原因第一CSS 文件没有被正确加载页面样式完全丢失这时打开控制台大概率是 CSS 文件 404基本都是publicPath或base配置错了第二引入的第三方 UI 库样式顺序变了打包后 CSS 被压缩合并某些覆盖样式失效解决方法是把自定义样式放到入口文件最后引入或者开启 CSS 模块化避免全局污染第三字体文件和图片路径不对构建后资源文件没有正确复制到 dist 目录需要检查打包配置里的 asset 处理规则。另外如果前端项目用到了 Web Worker 或者动态引入dynamic import的模块打包后这些异步加载的 chunk 也容易出现路径问题。排查思路很简单F12 打开开发者工具看 Network 面板里哪些请求 404 了然后顺着 URL 反推构建配置里对应的路径设置百分之八九十的问题都能通过 publicPath 修正解决。3.4 Webpack 打包优化配置的小经验如果项目体积大、首屏加载慢可以针对 Webpack 做几个常规优化。第一是开启 gzip 压缩Nginx 端开启gzip on前端可以在打包时用 compression-webpack-plugin 预生成.gz文件这样 Nginx 可以直接返回压缩包减少服务器 CPU 开销。第二是代码分割Webpack 的splitChunks配置可以把第三方库vendor与业务代码分离让浏览器缓存更持久。第三是生产环境关闭 source mapproductionSourceMap: false否则会大大增加打包体积也容易暴露源码。这些优化不是必须的但对于项目体量较大、用户分布广的场景收益很明显。具体的配置参数需要根据项目实际情况调整这里不展开每个插件的完整配置重点是理解“预压缩 代码分割 关闭调试信息”这三个方向。4. 后端打包实操Spring Boot 项目从 IDEA 到可执行 jar4.1 Maven 多模块项目的 package 流程Spring Boot 后端项目如果是单模块直接执行mvn clean package就好。但真实项目更多的是多模块结构比如 parent 工程下包含 common、system、admin 等多个子模块。这种项目打包时要特别注意打包顺序先安装被依赖的基础模块到本地仓库再打包可执行模块。如果直接在最外层执行mvn clean packageMaven 会根据 reactor 顺序自动处理模块依赖通常没问题但如果某个模块依赖的是本地仓库里不存在的快照版本就要先mvn install基础模块。另一个常见报错是“intellijmaven项目打包报错”表现形式五花八门编译失败、测试失败、依赖找不到。编译失败先看具体的报错信息很多时候是 Lombok 注解处理器与 JDK 版本不兼容导致的需要检查 Lombok 版本是否支持当前 JDK。测试失败可以执行mvn clean package -DskipTests跳过测试但建议先在本地跑一遍关键测试确认代码没大问题。依赖找不到则多半是私服地址没有配置或者某个依赖没有从远程仓库拉取成功。4.2 构建可执行 jar 的关键配置Spring Boot 项目要打成可执行的 fat jar包含内嵌 Tomcat 和所有依赖必须在 pom.xml 里配置spring-boot-maven-plugin。这个插件默认在mvn package阶段会重新打包生成的可执行 jar 和普通 jar 不同。配置里通常要指定mainClass作为启动入口。另外多环境配置可以结合 Maven profile 做资源过滤。比如在 pom.xml 里定义 prod 和 dev 两个 profile每个 profile 对应不同的application-{profile}.yml构建时用-Pprod指定激活哪个。这样打包出来的 jar 里已经包含了对应环境的默认配置再配合外置配置覆盖灵活性就很高。4.3 IDEA 里直接构建 Docker 镜像“idea 打包 docker镜像”这种需求本质上是在构建阶段生成镜像免去手动把 jar 包拷到服务器再写 Dockerfile 的操作。前提是你本机装了 Docker Desktop并且在 IDEA 里配置了 Docker 插件连接本地 Docker 守护进程。操作路径是在 IDEA 右侧的 Maven 面板里找到spring-boot:build-image这个 goalSpring Boot 2.3 提供双击执行插件会自动根据项目配置生成一个可运行镜像。这套方案用的是 Cloud Native Buildpacks 技术不需要编写 Dockerfile但生成的镜像名字和标签需要你提前在 pom.xml 里通过image配置指定。如果你的项目对基础镜像、启动命令有特殊要求还是建议自己写 Dockerfile 然后用命令行docker build -t 镜像名:标签 .构建。用 IDEA 构建镜像确实方便但我个人在实际项目中还是更倾向于在服务器上用 Dockerfile 构建原因有两个一是服务器构建出的镜像与运行时完全一致避免本机与服务器架构差异比如 Apple Silicon 的 arm64 镜像在 x86 服务器上有些基础镜像会有兼容性问题二是 CI/CD 流水线拉代码到服务器后直接构建流程更统一。5. Nginx 配置与前后台联调5.1 静态资源托管与 History 路由回退前端 dist 上传到服务器后Nginx 需要把它作为静态资源目录暴露出去。最简单配置如下server { listen 80; server_name your-domain.com; root /var/www/frontend/dist; index index.html; location / { try_files $uri $uri/ /index.html; } }这里最关键的就是try_files $uri $uri/ /index.html。它的作用是当用户访问/about这个路径时Nginx 先看有没有对应的实体文件$uri没有再找目录$uri/都找不到就回退到/index.html。这样 Vue Router 的 History 模式刷新页面就不会 404。如果你的前端项目用了 Hash 路由这个配置可以省略但我还是建议配置上因为不排除有的页面通过 URL 直接访问。5.2 反向代理解决跨域与接口转发前端页面能正常打开了接下来要让页面里的接口请求打到后端服务。假设前端请求统一带/api前缀经过 Nginx 转发到 Spring Boot 服务的http://127.0.0.1:8080配置如下location /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/带斜杠时Nginx 会把请求 URI 中匹配到的/api/前缀去掉再转发所以前端请求/api/user/list会变成后端/user/list。如果你不想去掉前缀就把proxy_pass配成http://127.0.0.1:8080不带斜杠后端接收到的还是/api/user/list。这个规则容易混淆每次配完最好用 curl 实测一下转发效果。5.3 静态资源缓存策略与 gzip 压缩前端静态资源带 hash 的文件名意味着内容变了文件名就变非常适合长期缓存。可以在 Nginx 里针对这类文件做强缓存location /assets/ { expires 30d; add_header Cache-Control public, immutable; }而 index.html 不能被缓存否则前端发版后用户浏览器还停留在旧页面。可以单独设置location /index.html { add_header Cache-Control no-cache; }。gzip 压缩同样在 Nginx 层开启即可gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xmlrss image/svgxml; gzip_min_length 1k;如果前端构建时已经用插件预生成了.gz文件可以配合gzip_static on直接返回预压缩文件减少服务器端压缩的 CPU 开销。5.4 多个不同结构的项目共用 Nginx 的问题热词里有“nginx部署多个web项目”这在实际工作中也很常见。如果一台服务器上要跑多个前后台分离项目每个项目分配不同的 server_name 或不同的 location 前缀即可。用不同域名区分时写多个 server 块用同一域名不同路径区分时在 location 层级做隔离。后一种情况要注意多个前端项目共用一个域名时之前说的 History 路由回退try_files ... /index.html可能互相覆盖。比如项目 A 挂在/a/下项目 B 挂在/b/下配置必须写成location ^~ /a/ { alias /var/www/project-a/; try_files $uri $uri/ /a/index.html; }。这里的 alias 和 try_files 回退路径都要带上前缀非常容易出错。我建议能用子域名区分就用子域名区分配置简单项目之间彻底隔离排查问题也方便。6. Docker 容器化部署与生产环境落地6.1 后端 Dockerfile 编写与镜像构建后端容器化的核心是写一个干净的 Dockerfile。我用得比较多的是多阶段构建虽然对单模块项目稍显冗余但能控制最终镜像体积。下面是一个简化的两阶段后端 Dockerfile# 构建阶段 FROM maven:3.8-openjdk-11 AS builder WORKDIR /build COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn clean package -DskipTests # 运行阶段 FROM openjdk:11-jre-slim WORKDIR /app COPY --frombuilder /build/target/demo.jar app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, -Dspring.profiles.activeprod, app.jar]第一段负责构建第二段只拷贝构建产物镜像里不会残留 Maven 和源码体积小很多。如果你的项目是纯单模块且构建时间不长也可以把 Dockerfile 简化成只包含运行阶段手动把 jar 拷进去FROM openjdk:11-jre-slim WORKDIR /app COPY demo.jar app.jar ENTRYPOINT [java, -jar, app.jar]这里有一个生产上必须注意的细节容器内进程要以非 root 用户运行。可以在 Dockerfile 里创建专用用户避免容器权限过大。Jenkins 或 GitLab CI 构建时镜像标签建议用构建时间和 Git commit 组合比如demo:20250518-3f2a9c1这样回滚时可以精确定位到代码版本。6.2 前端 Dockerfile 与 Nginx 基础镜像组合前端容器化有两种思路一种是把打包出来的 dist 目录挂载到宿主机 Nginx 上Nginx 装在宿主机另一种是前端也容器化用 nginx 镜像承载静态资源。第二种更干净迁移和扩展都方便。前端容器化的典型做法是两个阶段第一阶段用 node 镜像执行构建第二阶段把 dist 目录复制到 nginx 镜像中覆盖默认的/usr/share/nginx/html。同时把配置好的 nginx.conf 也复制进去# 构建阶段 FROM node:18-alpine AS builder WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci COPY . . RUN npm run build # 运行阶段 FROM nginx:1.24-alpine COPY --frombuilder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD [nginx, -g, daemon off;]这样构建出的前端镜像自带 Nginx 配置部署时只需要把后端地址通过环境变量传入即可。为了让后端地址不写死在 nginx.conf 里可以在启动脚本里用 envsubst 替换模板变量或者通过 docker-compose 的 environment 传递再用自定义 entrypoint 渲染配置。这个技巧在微服务场景下非常有用一个镜像可以部署到多个环境配置由运行时注入。6.3 docker-compose 一键编排前后台服务当前台、后台都要容器化之后用 docker-compose 编排是最有效率的方式。一个简单的docker-compose.yml示例如下version: 3.8 services: frontend: image: my-frontend:latest ports: - 80:80 depends_on: - backend restart: always backend: image: my-backend:latest ports: - 8080:8080 environment: SPRING_PROFILES_ACTIVE: prod DB_HOST: mysql REDIS_HOST: redis depends_on: - mysql - redis restart: always mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: demo volumes: - mysql-data:/var/lib/mysql restart: always redis: image: redis:7-alpine volumes: - redis-data:/data restart: always volumes: mysql-data: redis-data:这个编排文件里数据库和 Redis 也给容器化了数据通过 volume 持久化。生产环境如果数据库有备份需求、主从复制需求建议单独管理数据库服务不一定要放进 compose 里。compose 部署时先docker compose build构建镜像再docker compose up -d启动服务最后用docker compose ps查看所有服务状态。如果服务起不来用docker compose logs -f查看日志排查。关于 hot restart 的问题compose 文件里的restart: always保证了服务器重启后容器自动拉起来这是生产环境必须具备的。另外当你更新了某张后端镜像后执行docker compose up -d --build时compose 会检测到镜像变化后重建容器这个流程可以用来做简单版本的滚动发布。6.4 Redis、MySQL 等依赖服务的容器化部署要点Redis 用 Docker 部署非常简单一个命令就能跑起来。但生产环境用 Docker 起 Redis 要注意一定要挂载数据卷否则容器删除后数据全部丢失Redis 默认没有密码认证如果端口暴露在外网一定会被扫描爆破。建议通过--requirepass设置强密码或者在 compose 文件里通过command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes配置。MySQL 用 Docker 部署要特别注意字符集和时区问题。MySQL 8.0 默认字符集是 utf8mb4一般够用但如果业务上有特殊字符需求需要在启动参数或配置文件里显式指定。时区问题建议在连接 URL 里显式指定serverTimezoneAsia/Shanghai避免后端和数据库时区不一致导致时间数据错乱。数据卷挂载是必须的同时定期做逻辑备份不能只依赖 Docker volume防止存储节点故障导致数据彻底丢失。6.5 容器化部署的监控与日志部署上去不代表就完事了。生产环境一定要有基本的监控和日志收集。最简单的方式是看 Docker 日志docker compose logs -f --tail100 backend。但这只适合登录服务器排查问题。如果项目规模再大一点可以引入 Prometheus 监控和 Grafana 展示把 Node Exporter、cAdvisor 等指标采集起来。这个方向我在另一个项目里专门整理过完整的监控方案核心是用 Prometheus 抓取指标、Grafana 做可视化看板、Alertmanager 做告警通知。日志方面容器日志默认输出到 stdout然后由 Docker 接管。如果要更精细地做日志分析可以把日志挂载出来或用日志采集组件。对中小项目我建议先把 Nginx access log 和 Spring Boot 日志目录挂载到宿主机固定目录方便后续对接采集工具。7. 常见问题与排查技巧实录7.1 高频问题速查表我把实战中遇到的高频问题整理成一张表方便大家对照排查现象可能原因排查与解决前端页面白屏控制台 JS/CSS 404publicPath或base配置错误打开 Network 看失败资源 URL根据部署路径修正构建配置页面刷新后 404Vue Router History 模式没有配置回退Nginx 加try_files $uri $uri/ /index.html;接口请求失败报跨域错误前端请求了不同源的后端地址统一改用相对路径/api由 Nginx 反向代理后端启动报端口被占用宿主机端口或容器端口冲突用lsof -i:8080排查占用进程修改端口映射容器内连不上宿主机数据库数据库地址写成了 localhost容器内 localhost 是容器自己宿主机数据库要用宿主机局域网 IP 或 host 网络模式jar 包启动报 class 版本错误构建 JDK 与运行 JDK 版本不一致统一 JDK 大版本重新打包Docker 构建时 Maven 下载依赖太慢国内网络访问 Maven 中央仓库慢配置阿里云等镜像加速或在构建阶段挂载本机 maven 仓库缓存前后端都启动后前端仍显示 502Nginx 代理的后端地址不通在服务器上 curl 后端接口地址确认后端进程和端口正常7.2 一套好用的排查思路排查前后台分离部署问题我习惯按照“链路排查法”从浏览器一步步往后端推进。第一步看浏览器 Network 面板确认页面资源和接口请求的状态码。如果 HTML 都能加载、CSS/JS 200但页面空白优先怀疑 JS 运行时错误看 Console 面板。如果接口 404说明 Nginx 代理路径或后端接口路径不匹配如果 502说明 Nginx 无法连接到后端服务如果 504说明后端服务响应超时。确定问题出在 Nginx 或后端之后直接上服务器 curl 验证。比如后端接口 502我先执行curl -v http://127.0.0.1:8080/api/test看后端是否正常返回。如果不通看后端日志如果通再看 Nginx 转发配置。这套方法看起来基础但在紧张的上线时间窗里能最快把问题定位到具体环节。还有个很容易被忽略的地方前后台分离项目部署后前端请求的接口必须与 Nginx 反向代理规则一一对应。如果前后端约定接口前缀是/prod-api但前端代码里的 baseURL 写的是/api即使 Nginx 只代理了/prod-api请求也会全部 404。前端接口前缀、后端 context-path、Nginx location 三者必须构成同一条链路这是部署前的前置检查项。7.3 部署时环境变量与敏感信息的管理这一节专门聊聊部署里的环境变量与敏感信息管理。很多人在生产环境踩的坑都源于配置写死。比如数据库密码写死在application.yml里项目开源或代码仓库被多人访问时密码直接泄露。比较实用的做法是本地开发用本地配置生产环境通过环境变量注入敏感信息。Spring Boot 原生支持环境变量覆盖配置项比如SPRING_DATASOURCE_PASSWORD这种环境变量名会自动映射到spring.datasource.password配置项。Docker Compose 部署时可以使用.env文件配合${VARIABLE}语法environment: SPRING_DATASOURCE_URL: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}?useUnicodetruecharacterEncodingutf8 SPRING_DATASOURCE_USERNAME: ${DB_USER} SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}.env文件不要提交到版本控制并在服务器上严格控制权限。如果项目对安全的敏感度高也可以集成更专业的机密管理工具但对绝大多数前后台分离项目而言环境变量方案已经够用且容易落地。再补充一个线上环境常见的细节后端服务健康检查。Spring Boot 项目可以引入 Actuator暴露/actuator/health端点配合 docker-compose 的 healthcheck 配置。这样编排工具可以感知到后端是否就绪避免前端服务已经起来了后端还在启动中导致依赖它的请求全部失败。前端容器也没有必要因为后端还没有就绪就反复重启配好 depends_on 的条件即可按需等待。7.4 常用的网络连通性排查工具服务器上排查问题时curl 和 telnet 这两个工具要熟练。curl可以测试接口是否通、返回什么状态码、响应头是否正确。telnet则用来检测端口连通性比如telnet 192.168.1.10 3306检查 MySQL 端口是否可达。如果端口不通检查防火墙、安全组规则、容器端口映射。还有一个很实用的小技巧Nginx 配置修改后一定先执行nginx -t验证语法再执行nginx -s reload热加载。千万不要直接重启 Nginx否则配置里有语法错误服务直接挂掉影响所有正在运行的站点。热加载相比重启的优势在于平滑不会中断现有连接。8. 前后台分离部署的一条龙实战复盘看完前面的分环节拆解我再用一个完整小项目的流程做个串联复盘这样大家对整体节奏会更有体感。假设项目是 Vue 3 Spring Boot 2.7代码托管在 Git 仓库服务器是 Linux域名暂用 IP。第一步在本地把前后端代码分别 build 一遍。前端执行npm run build确认 dist 目录生成后端执行mvn clean package -DskipTests确认 jar 包生成。这一步能提前暴露绝大多数构建问题。第二步把前端 dist 目录上传到服务器指定目录比如/opt/www/frontend/dist。后端 jar 包上传到/opt/app/backend。同时把生产环境外置配置文件也放好比如/opt/app/backend/config/application-prod.yml。第三步配置 Nginx。把前面提到的静态托管、History 回退、/api反代三块配置写到/etc/nginx/conf.d/default.conf。配置好后执行nginx -t验证然后nginx -s reload。第四步启动后端。可以用 nohup 直接启动也可以用 systemd 管理生产环境建议 systemd。命令大概是这样cd /opt/app/backend nohup java -jar -Dspring.profiles.activeprod demo.jar app.log 21 启动后curl http://127.0.0.1:8080/api/health确认接口正常。第五步打开浏览器访问服务器公网 IP如果一切正常页面能打开、接口能通部署即完成。如果异常按前面第七节的链路排查法逐步定位。整个过程如果熟练半小时内就能完成一次手动部署。但这里面有一个漫长的沟第一次部署时前端 publicPath、Nginx 代理路径、后端外置配置这三者可能来回调好几次才能对上。所以我的建议是先在测试环境完整走一遍这套流程记录每一步的配置项形成部署文档。以后每次发版照着文档操作效率和稳定性都会好很多。9. 关于部署方式的几条真实建议最后聊点我个人的体会。前后台分离项目的部署方式没有绝对标准关键看团队规模和发布频率。如果你是自己维护一个小项目手动打包 Nginx nohup 完全够用不需要为了“上 Docker”而上 Docker。但一旦有两个人以上协作、或者需要频繁发版容器化几乎是必须的因为它能保证“本地能跑服务器就能跑”。热词里有一句“无法将此项目用于本地聊天”这让我联想到另一个容易踩的坑很多看似能把项目快速跑起来的工具或框架在本地 Demo 阶段表现完美但要做成真正可部署、可交付的项目时需要补齐的工程化细节远比想象多。前后台分离项目的部署也是这样开发环境顺风顺水真正落到打包部署这步才是检验项目完整度的时刻。再说说 CI/CD。前面讲的所有步骤其实都可以自动化。前端提交代码后自动 build、自动上传服务器后端提交后自动打包镜像、推送镜像仓库服务器端通过 webhook 拉取最新版本再重启。这套流程做下来发版从“手忙脚乱”变成“一键完成”。即使暂时不打算上完整的 CI/CD我也建议把部署脚本写在仓库里比如deploy.sh把构建、上传、重启这些命令固化下来。这样新人接手也能照着跑降低部署环节的知识门槛。前后台分离打包部署这件事本质上没有高深技术但细节密度非常高。配置项多、链路长、层级多任何一个环节的疏漏都可能让整个服务跑不起来。但只要把架构理清楚、把每一步的配置逻辑搞明白、把常见坑提前规避掉这就是一项稳定可靠的日常操作。希望这篇文章能帮你在部署这条路上少踩几个坑把宝贵的时间留给真正需要解决的问题。
返回列表