前后端部署实战:从开发到高可用的完整指南
在现代Web开发中,前后端分离已成为标准架构。但很多团队在前后端部署环节依然面临环境不一致、跨域问题、版本混乱、回滚困难等痛点。本文将系统梳理前后端部署的核心策略,并通过一个完整案例演示如何构建稳健的部署流水线。

一、前后端部署的本质与挑战
1.1 为什么需要区分前后端部署?
前端(如Vue、React)生成静态资源(HTML、CSS、JS),依赖浏览器运行时;后端(如Spring Boot、Node.js)提供服务API,依赖服务器运行时。两者的构建方式、运行环境、扩缩容策略截然不同:
| 维度 | 前端部署 | 后端部署 |
|---|---|---|
| 产物 | 静态文件(dist/) | Jar/War/容器镜像 |
| 运行环境 | Nginx/CDN | JVM/Node运行时 |
| 扩缩容 | 利用CDN边缘节点 | 水平扩展应用实例 |
| 配置管理 | .env文件,构建时注入 | 环境变量/配置中心 |
因此,前后端部署必须分开规划构建、发布与监控,同时又要通过网关(如Nginx、Kong)无缝连接。
1.2 常见陷阱
- 跨域配置错误:前后端部署在不同域名/端口时,CORS缺失或Nginx代理未正确传递头部。
- 静态资源缓存失效:前端构建后的文件名包含hash,但旧版本依然被CDN缓存。
- 环境变量硬编码:前端在构建时注入后端API地址,导致一个构建产物无法同时用于测试与生产。
- 回滚不一致:前端回滚到旧版本,后端API却新老不兼容。
二、前后端部署的现代架构与工具链
2.1 推荐架构:容器化 + 反向代理 + CI/CD
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 用户请求 │ ──▶ │ Nginx │ ──▶ │ 后端实例 │
│ (浏览器) │ │ (代理/SSL) │ │ (docker) │
└─────────────┘ └──────┬──────┘ └─────────────┘│┌──────▼──────┐│ 静态资源 ││ (CDN/Nginx)│└─────────────┘
- Nginx:负责SSL终止、静态资源托管、API请求转发(避免跨域)、负载均衡。
- 容器化:前后端各自构建Docker镜像,使用Docker Compose或Kubernetes编排。
- CI/CD:每个提交自动触发构建→单元测试→构建镜像→部署到预发布环境→集成测试→生产部署。
2.2 关键实践
- 构建时注入环境变量:前端在CI/CD流水线中通过
VITE_API_BASE_URL等变量动态生成配置,而非硬编码。 - Nginx location规则:将
/api/前缀的请求转发至后端服务,其余请求指向前端静态目录。 - 健康检查与优雅停止:后端容器提供
/health端点;Nginx通过proxy_pass配合proxy_next_upstream实现故障转移。 - 灰度发布:利用Nginx的
split_clients或K8s的Service流量权重,逐步切换前后端版本。
三、实战案例:使用Docker+Nginx部署Vue+SpringBoot
3.1 项目结构与Dockerfile
前端 (vue-app):
# 多阶段构建
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
ARG VITE_API_BASE_URL=http://backend:8080
RUN VITE_API_BASE_URL=${VITE_API_BASE_URL} npm run buildFROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
后端 (spring-boot-app):
FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTestsFROM eclipse-temurin:17-jre-alpine
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
3.2 Nginx 配置(统一代理)
upstream backend {server spring-boot-app:8080;
}server {listen 80;server_name example.com;# 静态资源(前端)location / {root /usr/share/nginx/html;try_files $uri $uri/ /index.html; # SPA路由支持expires 1y;add_header Cache-Control "public, immutable";}# API代理(后端)location /api/ {proxy_pass http://backend;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 30s;proxy_read_timeout 60s;proxy_next_upstream error timeout invalid_header http_500 http_502;}
}
3.3 Docker Compose 编排
version: '3.8'
services:nginx:build: ./vue-appports:- "80:80"depends_on:- spring-boot-appspring-boot-app:build: ./spring-boot-appenvironment:- SPRING_PROFILES_ACTIVE=prod- DB_URL=jdbc:postgresql://postgres:5432/appdbdepends_on:- postgrespostgres:image: postgres:15-alpineenvironment:POSTGRES_DB: appdbPOSTGRES_PASSWORD: secretvolumes:- pgdata:/var/lib/postgresql/data
volumes:pgdata:
启动命令:docker compose up -d --build
3.4 CI/CD 流水线要点(GitHub Actions)
name: Deploy
on:push:branches: [ main ]
jobs:deploy:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- name: Build & Push Imagesrun: |docker compose builddocker tag vue-app:latest myregistry/vue-app:${{ github.sha }}docker tag spring-boot-app:latest myregistry/spring-boot-app:${{ github.sha }}docker push myregistry/vue-app:${{ github.sha }}docker push myregistry/spring-boot-app:${{ github.sha }}- name: Deploy to Serverenv:SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}run: |ssh -i key user@host "cd /opt/app && docker compose pull && docker compose up -d --remove-orphans"
四、总结与进阶建议
前后端部署不是简单的“把文件放服务器”,而是一套涉及构建、环境管理、反向代理、监控与回滚的工程体系。本文通过容器化 + Nginx + CI/CD 的方案,解决了环境一致性与自动化问题。后续你可以进一步探索:
- 灰度发布:Nginx 的
split_clients或者 K8s 的Canary Deployment。 - 前端SSR:若需SEO,可将Vue/React放在Node.js服务端渲染,部署方式变为Node后端+前端SSR服务。
- 可观测性:接入Prometheus + Grafana监控前后端性能指标。
掌握这些实战技术,你的前后端部署就能从“勉强可用”进阶到“高可用、可观测、可回滚”的企业级水准。
文章版权声明:除非注明,否则均为边学边练网络文章,版权归原作者所有