統一部署
本文檔說明如何使用 app-web-host 將前端 SPA 與 Spring Boot 統一打包部署。
架構概述
app-web (React SPA)
│
│ npm run build
▼
app-web/dist/
│
│ copyWebBuild (Gradle task)
▼
app-web-host/src/main/resources/static/
│
│ gradle build
▼
app-web-host.war(可部署的應用程式)
為什麼需要統一部署?
優點
- 簡化部署:單一 WAR 檔案包含前後端
- 安全性:透過 Spring Security 統一管理
- CSP Nonce:動態注入 CSP nonce 提升安全性
- SPA 路由:自動處理前端路由轉發
app-web-host 提供的功能
- SPA 路由轉發(所有非 API 路徑導向 index.html)
- CSP nonce 動態注入
- 安全 Headers 配置(HSTS、CSP、Referrer-Policy)
- 動態 base href 注入
建置流程
1. 建置前端
cd app-web
npm run build
2. 複製到 Host
cd ../app-web-host
./gradlew copyWebBuild
3. 建置 WAR
./gradlew clean build
4. 部署
cp build/libs/app-web-host.war /opt/tomcat/webapps/ROOT.war
一鍵建置
cd app-web-host
./gradlew clean deployBuild
此命令會依序執行:
- 清理舊建置
- 建置前端(
npm run build) - 複製前端到 static 目錄
- 建置 WAR
配置說明
application.yml
app:
web:
# SPA 路由配置
spa-routes:
- /products/**
- /orders/**
- /customers/**
- /settings/**
# 排除的路徑(不做 SPA 轉發)
exclude-paths:
- /api/**
- /actuator/**
- /static/**
security:
# CSP 配置
csp:
enabled: true
report-only: false
安全 Headers
app-web-host 自動配置以下安全 Headers:
| Header | 值 |
|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains |
Content-Security-Policy | 動態生成,包含 nonce |
X-Content-Type-Options | nosniff |
X-Frame-Options | DENY |
Referrer-Policy | strict-origin-when-cross-origin |
CSP Nonce 注入
運作方式
- 每個請求生成唯一的 nonce
- 注入到 index.html 的
<script>和<style>標籤 - CSP Header 包含對應的 nonce
index.html 範本
<!DOCTYPE html>
<html>
<head>
<script nonce="{{CSP_NONCE}}">
// inline script
</script>
</head>
<body>
<div id="root"></div>
<script nonce="{{CSP_NONCE}}" src="/assets/main.js"></script>
</body>
</html>
環境變數
| 變數 | 說明 | 預設值 |
|---|---|---|
APP_BASE_HREF | 應用程式基礎路徑 | / |
APP_API_URL | API 基礎 URL | /api |
故障排除
SPA 路由 404
確認路由已在 spa-routes 配置中:
app:
web:
spa-routes:
- /your-new-route/**
CSP 錯誤
檢查瀏覽器開發者工具的 Console,確認是否有 CSP 違規報告。
靜態資源 404
確認前端建置輸出已複製到 src/main/resources/static/。