feat: 配置简化为同源相对路径,统一 /api/ 路由约定
配合 zTools2 路由统一到 /api/,简化环境感知配置:
- app.config.js:去掉 BASE_URL 的 dev/prod 分支,iframe 与探针一律用同源相对路径
(/api/pdf、/api/health、/api/wb-page/{id}),默认空 baseUrl;保留 VITE_API_BASE 覆盖。
这样无论 dev(vite proxy)还是任意部署环境(反代),同源相对路径都自动指向当前环境 zTools2,
不再误打到 f.zikai.wang 等其它环境域名。
- vite.config.js:dev proxy 从 /api /pdf /health /static /upload /files /wb /ws 多条
简化为单条 /api(含 ws:true,覆盖 /api/ws WebSocket)。
- deploy.sh:Apache vhost 从多条 ProxyPass 简化为单条 /api/,a2enmod 增加 proxy_wstunnel。
- docs/deployment.md:更新拓扑/模式说明,新增路由约定(所有入口在 /api/ 下,反代只需一条规则)。
- 同步更新 zPDF_package 子模块指针(其 vite proxy 亦简化为单条 /api)。
This commit is contained in:
29
deploy.sh
29
deploy.sh
@@ -3,7 +3,7 @@
|
|||||||
#
|
#
|
||||||
# 生产拓扑:
|
# 生产拓扑:
|
||||||
# Apache(:80) -> 静态文件 /var/www/html(zMainPage 构建产物)
|
# Apache(:80) -> 静态文件 /var/www/html(zMainPage 构建产物)
|
||||||
# -> 反代 /api、/pdf、/pdf-admin、/ws 等到 zTools2(127.0.0.1:6867)
|
# -> 反代 /api/ 到 zTools2(127.0.0.1:6867)(页面/静态/探针/WS/API 全在 /api/ 下)
|
||||||
# zTools2(127.0.0.1:6867) -> MySQL(3306) + uploads/ 磁盘
|
# zTools2(127.0.0.1:6867) -> MySQL(3306) + uploads/ 磁盘
|
||||||
#
|
#
|
||||||
# 前提:zMainPage 与 zTools2 在同一主机(zMainPage 父项目,zTools2 同级目录)。
|
# 前提:zMainPage 与 zTools2 在同一主机(zMainPage 父项目,zTools2 同级目录)。
|
||||||
@@ -49,34 +49,19 @@ HT
|
|||||||
sudo cp /tmp/zmainpage_htaccess "$WEB_ROOT/.htaccess"
|
sudo cp /tmp/zmainpage_htaccess "$WEB_ROOT/.htaccess"
|
||||||
|
|
||||||
echo "==> [3/4] 配置 Apache 反代(zMainPage -> zTools2)"
|
echo "==> [3/4] 配置 Apache 反代(zMainPage -> zTools2)"
|
||||||
# 确保 proxy / rewrite / headers 模块启用
|
# 确保 proxy / rewrite / headers / proxy_wstunnel(WebSocket)模块启用
|
||||||
sudo a2enmod proxy proxy_http rewrite headers >/dev/null 2>&1 || true
|
sudo a2enmod proxy proxy_http proxy_wstunnel rewrite headers >/dev/null 2>&1 || true
|
||||||
# 写入 vhost 配置(仅当不存在时,避免覆盖已有 HTTPS 配置)
|
# 写入 vhost 配置(仅当不存在时,避免覆盖已有 HTTPS 配置)
|
||||||
VHOST="/etc/apache2/sites-available/zmainpage.conf"
|
VHOST="/etc/apache2/sites-available/zmainpage.conf"
|
||||||
if [[ ! -f "$VHOST" ]]; then
|
if [[ ! -f "$VHOST" ]]; then
|
||||||
sudo tee "$VHOST" >/dev/null <<'VH'
|
sudo tee "$VHOST" >/dev/null <<'VH'
|
||||||
<VirtualHost *:80>
|
<VirtualHost *:80>
|
||||||
DocumentRoot /var/www/html
|
DocumentRoot /var/www/html
|
||||||
# zTools2 反代:/api、/pdf、/pdf-admin、/static、/upload、/files、/wb、/ws 等转发到后端
|
# zTools2 反代:所有入口(页面/静态/探针/WS/API)统一在 /api/ 下,一条规则即可;
|
||||||
|
# WebSocket 走 /api/ws/wb/{id},由 proxy_wstunnel 透传 Upgrade 头
|
||||||
ProxyPreserveHost On
|
ProxyPreserveHost On
|
||||||
ProxyPass /api/ http://127.0.0.1:6867/api/
|
ProxyPass /api/ http://127.0.0.1:6867/api/
|
||||||
ProxyPassReverse /api/ http://127.0.0.1:6867/api/
|
ProxyPassReverse /api/ http://127.0.0.1:6867/api/
|
||||||
ProxyPass /pdf http://127.0.0.1:6867/pdf
|
|
||||||
ProxyPassReverse /pdf http://127.0.0.1:6867/pdf
|
|
||||||
ProxyPass /pdf-admin http://127.0.0.1:6867/pdf-admin
|
|
||||||
ProxyPassReverse /pdf-admin http://127.0.0.1:6867/pdf-admin
|
|
||||||
ProxyPass /static/ http://127.0.0.1:6867/static/
|
|
||||||
ProxyPassReverse /static/ http://127.0.0.1:6867/static/
|
|
||||||
ProxyPass /upload http://127.0.0.1:6867/upload
|
|
||||||
ProxyPassReverse /upload http://127.0.0.1:6867/upload
|
|
||||||
ProxyPass /files http://127.0.0.1:6867/files
|
|
||||||
ProxyPassReverse /files http://127.0.0.1:6867/files
|
|
||||||
ProxyPass /wb http://127.0.0.1:6867/wb
|
|
||||||
ProxyPassReverse /wb http://127.0.0.1:6867/wb
|
|
||||||
ProxyPass /wb-admin http://127.0.0.1:6867/wb-admin
|
|
||||||
ProxyPassReverse /wb-admin http://127.0.0.1:6867/wb-admin
|
|
||||||
ProxyPass /health http://127.0.0.1:6867/health
|
|
||||||
ProxyPassReverse /health http://127.0.0.1:6867/health
|
|
||||||
# SPA 回退:非文件非目录的请求回退到 index.html
|
# SPA 回退:非文件非目录的请求回退到 index.html
|
||||||
<Directory /var/www/html>
|
<Directory /var/www/html>
|
||||||
AllowOverride All
|
AllowOverride All
|
||||||
@@ -103,5 +88,5 @@ fi
|
|||||||
echo
|
echo
|
||||||
echo "部署完成。"
|
echo "部署完成。"
|
||||||
echo " - zMainPage: http://localhost(Apache :80,静态文件 + SPA)"
|
echo " - zMainPage: http://localhost(Apache :80,静态文件 + SPA)"
|
||||||
echo " - zTools2: http://127.0.0.1:6867(经 Apache 反代 /api /pdf 等)"
|
echo " - zTools2: http://127.0.0.1:6867(经 Apache 反代 /api/)"
|
||||||
echo " - PDF 页签: http://localhost/pdf -> iframe 同源嵌入 zTools2 /pdf"
|
echo " - PDF 页签: http://localhost -> iframe 同源嵌入 zTools2 /api/pdf"
|
||||||
|
|||||||
@@ -7,15 +7,17 @@ zPDF_package 功能涉及三个项目协同:**zMainPage**(父站,Vue3 静
|
|||||||
```
|
```
|
||||||
浏览器 -> Apache(:80)
|
浏览器 -> Apache(:80)
|
||||||
├── 静态文件 /var/www/html (zMainPage 构建产物:主页 + 页签)
|
├── 静态文件 /var/www/html (zMainPage 构建产物:主页 + 页签)
|
||||||
└── 反代 -> zTools2(127.0.0.1:6867)
|
└── 反代 /api/ -> zTools2(127.0.0.1:6867)
|
||||||
|
├── /api/pdf PDF 转换页面(iframe 嵌入源)
|
||||||
├── /api/pdf/* PDF 转换 API(cookie 用户)
|
├── /api/pdf/* PDF 转换 API(cookie 用户)
|
||||||
├── /pdf PDF 转换页面(iframe 嵌入源)
|
├── /api/pdf-admin PDF 管理页(Basic Auth)
|
||||||
├── /pdf-admin PDF 管理页(Basic Auth)
|
├── /api/static/pdf* 前端静态资源
|
||||||
├── /static/pdf* 前端静态资源
|
|
||||||
└── MySQL(3306) + uploads/
|
└── MySQL(3306) + uploads/
|
||||||
```
|
```
|
||||||
|
|
||||||
PDF 页签 = zMainPage 用 iframe 嵌入 zTools2 的 `/pdf` 页面(同源,cookie 第一方生效)。
|
PDF 页签 = zMainPage 用 iframe 嵌入 zTools2 的 `/api/pdf` 页面(**同源相对路径**,cookie 第一方生效,与环境无关)。
|
||||||
|
|
||||||
|
> **路由约定**:zTools2 所有入口(页面 / 静态 / 探针 / WS / API)统一挂在 `/api/` 下,反代与 vite proxy 只需一条 `/api/` 规则。前端 iframe 与 fetch 一律用同源相对路径(`/api/pdf`、`/api/health` 等),自动指向**当前环境**的 zTools2,无需区分 dev/prod,也不会误打到其它环境域名。详见 zTools2 README「路由约定」。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -32,7 +34,7 @@ cd zTools2
|
|||||||
# 或:python -m uvicorn app.main:app --host 127.0.0.1 --port 6867
|
# 或:python -m uvicorn app.main:app --host 127.0.0.1 --port 6867
|
||||||
```
|
```
|
||||||
|
|
||||||
访问:http://127.0.0.1:6867/pdf(PDF 页面)、http://127.0.0.1:6867/docs(API 文档)。
|
访问:http://127.0.0.1:6867/api/pdf(PDF 页面)、http://127.0.0.1:6867/docs(API 文档)。
|
||||||
|
|
||||||
### 2. zPDF_package 前端独立运行
|
### 2. zPDF_package 前端独立运行
|
||||||
|
|
||||||
@@ -42,7 +44,7 @@ npm install
|
|||||||
npm run dev # http://localhost:5175
|
npm run dev # http://localhost:5175
|
||||||
```
|
```
|
||||||
|
|
||||||
`vite.config.js` 已配代理:`/api/pdf/*` 与 `/api/admin/pdf/*` 转发到 `127.0.0.1:6867`(需 zTools2 在跑)。
|
`vite.config.js` 已配代理:`/api` 转发到 `127.0.0.1:6867`(需 zTools2 在跑),覆盖 `/api/pdf/*` 与 `/api/admin/pdf/*`。
|
||||||
|
|
||||||
### 3. zMainPage 独立运行
|
### 3. zMainPage 独立运行
|
||||||
|
|
||||||
@@ -55,7 +57,7 @@ npm install
|
|||||||
npm run dev # http://localhost:5173
|
npm run dev # http://localhost:5173
|
||||||
```
|
```
|
||||||
|
|
||||||
> 独立模式下 PDF 页签的 iframe 指向 `https://f.zikai.wang/pdf`(线上),如需指向本地 zTools2,改 `src/config/app.config.js` 的 `pdf.baseUrl` 为 `http://127.0.0.1:6867` 后重新 `npm run dev`。
|
> 独立模式下 PDF 页签的 iframe 用同源相对路径 `/api/pdf`,经 vite proxy 转发到本地 zTools2(127.0.0.1:6867)。如需指向其它环境的 zTools2,改 `src/config/app.config.js` 的 `pdf.baseUrl` 为该环境地址(含协议与域名)后重新 `npm run dev`,或设 `VITE_API_BASE` 环境变量。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -72,12 +74,12 @@ cd zMainPage
|
|||||||
`deploy.sh` 做的事:
|
`deploy.sh` 做的事:
|
||||||
1. 构建 zMainPage(含子模块),rsync 到 `/var/www/html`
|
1. 构建 zMainPage(含子模块),rsync 到 `/var/www/html`
|
||||||
2. 写入 `.htaccess`(SPA history 回退)
|
2. 写入 `.htaccess`(SPA history 回退)
|
||||||
3. 配置 Apache vhost(`/etc/apache2/sites-available/zmainpage.conf`)反代 `/api` `/pdf` `/pdf-admin` `/static` 等到 `127.0.0.1:6867`
|
3. 配置 Apache vhost(`/etc/apache2/sites-available/zmainpage.conf`)反代 `/api/` 到 `127.0.0.1:6867`(含 WebSocket,靠 proxy_wstunnel 透传 `/api/ws`)
|
||||||
4. 重启 zTools2(除非 `--no-restart`)
|
4. 重启 zTools2(除非 `--no-restart`)
|
||||||
|
|
||||||
部署后访问 http://localhost/ 即主页,PDF 页签 iframe 同源加载 `/pdf`。
|
部署后访问 http://localhost/ 即主页,PDF 页签 iframe 同源加载 `/api/pdf`。
|
||||||
|
|
||||||
> 已有 HTTPS vhost 时:`deploy.sh` 不会覆盖(仅首次写入)。手动在现有 vhost 加 `ProxyPass /pdf http://127.0.0.1:6867/pdf` 等规则即可。
|
> 已有 HTTPS vhost 时:`deploy.sh` 不会覆盖(仅首次写入)。手动在现有 vhost 加 `ProxyPass /api/ http://127.0.0.1:6867/api/` 一条规则即可(需 `a2enmod proxy_wstunnel` 以支持 WebSocket)。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -138,7 +140,7 @@ cd zTools2 && sudo systemctl restart ztools2
|
|||||||
| Python | ≥ 3.10(本仓开发用 3.14,需 SQLAlchemy ≥ 2.0.37) |
|
| Python | ≥ 3.10(本仓开发用 3.14,需 SQLAlchemy ≥ 2.0.37) |
|
||||||
| Node.js | ≥ 18 |
|
| Node.js | ≥ 18 |
|
||||||
| MySQL | 8.x |
|
| MySQL | 8.x |
|
||||||
| Apache | 2.4(启用 proxy / proxy_http / rewrite / headers) |
|
| Apache | 2.4(启用 proxy / proxy_http / proxy_wstunnel / rewrite / headers) |
|
||||||
| weasyprint 系统库 | libpango-1.0-0 / libpangoft2-1.0-0 / libcairo2 / libgdk-pixbuf-2.0-0 |
|
| weasyprint 系统库 | libpango-1.0-0 / libpangoft2-1.0-0 / libcairo2 / libgdk-pixbuf-2.0-0 |
|
||||||
|
|
||||||
## 防火墙
|
## 防火墙
|
||||||
|
|||||||
@@ -2,41 +2,38 @@
|
|||||||
// 模块按需 import { appConfig } 使用,改 URL 只改这里即可(需重新 build)。
|
// 模块按需 import { appConfig } 使用,改 URL 只改这里即可(需重新 build)。
|
||||||
// 每个服务项都带默认值,避免缺失字段导致渲染崩溃。
|
// 每个服务项都带默认值,避免缺失字段导致渲染崩溃。
|
||||||
//
|
//
|
||||||
// 环境感知(测试环境指向测试环境,生产环境指向生产环境):
|
// 路由约定:zTools2 所有入口(页面/静态/探针/WS/API)统一挂在 /api/ 下,
|
||||||
// - 开发服务器(vite dev / MODE=development):baseUrl 为空串(同源),
|
// iframe 与 fetch 一律用**同源相对路径**(/api/pdf、/api/health 等)。
|
||||||
// 经 vite.config.js 的 server.proxy 把 /api /pdf /health /static 等同源代理到
|
// 无论是 vite dev(server.proxy 转发 /api 到本地 zTools2)、还是任意部署环境
|
||||||
// 本地 zTools2(127.0.0.1:6867),使 iframe 与 fetch 都命中本地服务。
|
// (Apache/Nginx 反代 /api 到当前环境的 zTools2),同源相对路径都自动指向
|
||||||
// - 生产构建(vite build / MODE=production):baseUrl 指向线上 f.zikai.wang(同源)。
|
// **当前环境**的服务,无需区分 dev/prod,也不会误打到其它环境域名。
|
||||||
// - 可用 VITE_API_BASE 覆盖(如自定义测试环境域名,需含协议)。
|
// 罕见需要时可设 VITE_API_BASE(含协议与域名)显式覆盖为绝对地址。
|
||||||
|
|
||||||
// 生产构建用线上地址(同源);开发用空串(同源,经 vite proxy 转发到本地 zTools2);
|
// 默认空串 = 同源相对路径;VITE_API_BASE 可覆盖为绝对地址(如指向独立测试环境域名)
|
||||||
// 允许 VITE_API_BASE 显式覆盖(如指向独立测试环境域名)
|
const BASE_URL = import.meta.env.VITE_API_BASE || ''
|
||||||
const BASE_URL =
|
|
||||||
import.meta.env.VITE_API_BASE ||
|
|
||||||
(import.meta.env.PROD ? 'https://f.zikai.wang' : '')
|
|
||||||
|
|
||||||
export const appConfig = {
|
export const appConfig = {
|
||||||
// 共享记事本(白板)服务
|
// 共享记事本(白板)服务
|
||||||
whiteboard: {
|
whiteboard: {
|
||||||
// 服务根地址(含协议与域名)
|
// 服务根地址(含协议与域名);默认空串 = 同源相对路径
|
||||||
baseUrl: BASE_URL,
|
baseUrl: BASE_URL,
|
||||||
// 存活探针路径;周期探测,挂掉则隐藏页签并卸载组件
|
// 存活探针路径;周期探测,挂掉则隐藏页签并卸载组件
|
||||||
healthPath: '/health',
|
healthPath: '/api/health',
|
||||||
// 记事本页面路径生成器
|
// 记事本页面路径生成器
|
||||||
pagePath: (boardId) => `/wb/${encodeURIComponent(boardId)}`,
|
pagePath: (boardId) => `/api/wb-page/${encodeURIComponent(boardId)}`,
|
||||||
// 默认打开的记事本 id
|
// 默认打开的记事本 id
|
||||||
defaultBoardId: 'share',
|
defaultBoardId: 'share',
|
||||||
// 探测超时(毫秒)
|
// 探测超时(毫秒)
|
||||||
healthTimeoutMs: 4000
|
healthTimeoutMs: 4000
|
||||||
},
|
},
|
||||||
// PDF 转换服务(zTools2 托管的 /pdf 页面,iframe 同源嵌入)
|
// PDF 转换服务(zTools2 托管的 /api/pdf 页面,iframe 同源嵌入)
|
||||||
pdf: {
|
pdf: {
|
||||||
// 服务根地址(含协议与域名)
|
// 服务根地址(含协议与域名);默认空串 = 同源相对路径
|
||||||
baseUrl: BASE_URL,
|
baseUrl: BASE_URL,
|
||||||
// 存活探针路径;周期探测,挂掉则隐藏页签并卸载组件
|
// 存活探针路径;周期探测,挂掉则隐藏页签并卸载组件
|
||||||
healthPath: '/health',
|
healthPath: '/api/health',
|
||||||
// PDF 转换页面路径
|
// PDF 转换页面路径
|
||||||
pagePath: '/pdf',
|
pagePath: '/api/pdf',
|
||||||
// 探测超时(毫秒)
|
// 探测超时(毫秒)
|
||||||
healthTimeoutMs: 4000
|
healthTimeoutMs: 4000
|
||||||
}
|
}
|
||||||
@@ -45,7 +42,7 @@ export const appConfig = {
|
|||||||
/**
|
/**
|
||||||
* 取某服务的存活探针 URL。
|
* 取某服务的存活探针 URL。
|
||||||
* @param {keyof typeof appConfig} service 配置中的服务名
|
* @param {keyof typeof appConfig} service 配置中的服务名
|
||||||
* @returns {string} 完整探针 URL,如 https://f.zikai.wang/health
|
* @returns {string} 完整探针 URL,如同源相对 /api/health 或绝对地址
|
||||||
*/
|
*/
|
||||||
export function healthUrl(service) {
|
export function healthUrl(service) {
|
||||||
const cfg = appConfig[service]
|
const cfg = appConfig[service]
|
||||||
|
|||||||
2
third_party/zPDF_package
vendored
2
third_party/zPDF_package
vendored
Submodule third_party/zPDF_package updated: 30f5cee4a1...8482917e88
@@ -62,39 +62,13 @@ export default defineConfig({
|
|||||||
target: 'http://localhost:8080',
|
target: 'http://localhost:8080',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
},
|
},
|
||||||
// zTools2 后端同源代理:开发环境把 /api /pdf /health /static 等转发到本地 zTools2,
|
// zTools2 后端同源代理:所有入口(页面/静态/探针/WS/API)统一在 /api/ 下,
|
||||||
// 使 iframe(/pdf)与 fetch(/api/pdf/*)同源命中本地服务(测试环境指向测试环境)。
|
// 一条 /api 规则即可覆盖 iframe(/api/pdf)与 fetch(/api/pdf/*)。
|
||||||
// 生产构建时 app.config.js 的 baseUrl 指向线上 f.zikai.wang,不走此代理。
|
// ws:true 让 /api/ws/wb/{id} 的 WebSocket 也走此代理。
|
||||||
|
// 同源相对路径与环境无关:dev 命中本地 zTools2,生产由反代命中当前环境 zTools2。
|
||||||
'/api': {
|
'/api': {
|
||||||
target: 'http://127.0.0.1:6867',
|
target: 'http://127.0.0.1:6867',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
},
|
|
||||||
'/pdf': {
|
|
||||||
target: 'http://127.0.0.1:6867',
|
|
||||||
changeOrigin: true,
|
|
||||||
},
|
|
||||||
'/health': {
|
|
||||||
target: 'http://127.0.0.1:6867',
|
|
||||||
changeOrigin: true,
|
|
||||||
},
|
|
||||||
'/static': {
|
|
||||||
target: 'http://127.0.0.1:6867',
|
|
||||||
changeOrigin: true,
|
|
||||||
},
|
|
||||||
'/upload': {
|
|
||||||
target: 'http://127.0.0.1:6867',
|
|
||||||
changeOrigin: true,
|
|
||||||
},
|
|
||||||
'/files': {
|
|
||||||
target: 'http://127.0.0.1:6867',
|
|
||||||
changeOrigin: true,
|
|
||||||
},
|
|
||||||
'/wb': {
|
|
||||||
target: 'http://127.0.0.1:6867',
|
|
||||||
changeOrigin: true,
|
|
||||||
},
|
|
||||||
'/ws': {
|
|
||||||
target: 'ws://127.0.0.1:6867',
|
|
||||||
ws: true,
|
ws: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user