docs: update production mobile deployment runbook
Some checks failed
CI / verify (push) Has been cancelled
Some checks failed
CI / verify (push) Has been cancelled
Sync the CDN origin, five-node cache policy, audio compatibility routing, validation, rollback, and current branch baseline. Made-with: Proma
This commit is contained in:
@@ -1,20 +1,23 @@
|
|||||||
# frontend-miniapp 正式环境部署手册
|
# frontend-miniapp 正式环境部署手册
|
||||||
|
|
||||||
最后更新:2026-07-24(同步五节点 `17083` 缓存策略修复及逐节点验收)
|
最后更新:2026-07-28(同步 CDN 源站域名、五节点缓存策略、讲解音频兼容路由及 CDN 验收/回滚流程)
|
||||||
|
|
||||||
## 适用范围
|
## 适用范围
|
||||||
|
|
||||||
本文档适用于将本地仓库 `F:\深圳自然博物馆\frontend-miniapp` 的 H5 产物部署到深圳自然博物馆正式环境。
|
本文档适用于将本地仓库 `E:\深圳自然博物馆\workplace\frontend-miniapp` 的 H5 产物部署到深圳自然博物馆正式环境。
|
||||||
|
|
||||||
- 正式域名:`https://guide.sznhmuseum.org.cn`
|
- 正式域名:`https://guide.sznhmuseum.org.cn`
|
||||||
|
- CDN 源站域名:`https://guide-real.sznhmuseum.org.cn`(只供 CDN 回源和源站排障,不作为游客入口)
|
||||||
|
- 源站公网 IP:`218.17.240.244`
|
||||||
- 主节点:`172.20.14.21`
|
- 主节点:`172.20.14.21`
|
||||||
- 部署目录:`/data/nginx/html/mobile`
|
- 部署目录:`/data/nginx/html/mobile`
|
||||||
- Nginx 容器:`sgs-nginx`(`nginx/1.30.3`,Docker host 网络)
|
- Nginx 容器:`sgs-nginx`(`nginx/1.30.3`,Docker host 网络)
|
||||||
- Nginx 生效配置目录:`/data/nginx/conf.d`(容器内 `/etc/nginx/conf.d`,只读挂载)
|
- Nginx 生效配置目录:`/data/nginx/conf.d`(容器内 `/etc/nginx/conf.d`,只读挂载)
|
||||||
- 同步脚本:`/data/scripts/sync-frontend-nodes.sh`
|
- 同步脚本:`/data/scripts/sync-frontend-nodes.sh`
|
||||||
- Nginx 配置变更记录:2026-07-24,五台 `17083` 已统一 assets/字体缓存及静态资源 404 防 SPA 回退规则
|
- Nginx 配置变更记录:2026-07-28,`.21` 公网入口及五台 `17083` 已完成 CDN 源站、分层缓存、静态资源 404 防 SPA 回退和音频兼容路由适配
|
||||||
- 同步节点:`172.20.14.23`、`172.20.14.26`、`172.20.14.27`、`172.20.14.33`
|
- 同步节点:`172.20.14.23`、`172.20.14.26`、`172.20.14.27`、`172.20.14.33`
|
||||||
- 远程仓库:`http://192.168.0.93:3333/lyf/frontend-miniapp.git`
|
- 远程仓库:`https://git.whaoyue.com/lyf/frontend-miniapp.git`
|
||||||
|
- 本次文档同步基线:分支 `codex/import-sgs-frontend-mobile-20260727`,提交 `fc93b8d7d32a208a037be576ce3b9da2db3c1fe3`(仅表示仓库同步基线,不表示该提交已部署到生产)
|
||||||
|
|
||||||
不要把服务器密码、证书私钥、token、真实后台账号、腾讯地图正式 key 写入仓库文档或提交记录。
|
不要把服务器密码、证书私钥、token、真实后台账号、腾讯地图正式 key 写入仓库文档或提交记录。
|
||||||
|
|
||||||
@@ -23,7 +26,7 @@
|
|||||||
进入项目目录:
|
进入项目目录:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
cd 'F:\深圳自然博物馆\frontend-miniapp'
|
cd 'E:\深圳自然博物馆\workplace\frontend-miniapp'
|
||||||
```
|
```
|
||||||
|
|
||||||
检查分支、远程仓库和本地改动:
|
检查分支、远程仓库和本地改动:
|
||||||
@@ -80,11 +83,13 @@ Saved working directory and index state On master: pre-deploy-prod-local-fixes-Y
|
|||||||
STASHED=pre-deploy-prod-local-fixes-YYYYMMDDHHmmss
|
STASHED=pre-deploy-prod-local-fixes-YYYYMMDDHHmmss
|
||||||
```
|
```
|
||||||
|
|
||||||
拉取远程最新代码:
|
拉取目标发布分支。发布前必须由变更单或版本记录明确分支名,不得默认把 `master` 当作本次目标:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
|
$branch = 'codex/import-sgs-frontend-mobile-20260727'
|
||||||
git fetch origin
|
git fetch origin
|
||||||
git pull --ff-only origin master
|
git switch $branch
|
||||||
|
git pull --ff-only origin $branch
|
||||||
git log -1 --pretty=format:'%h %s'
|
git log -1 --pretty=format:'%h %s'
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -103,15 +108,26 @@ git status --short --branch --untracked-files=all
|
|||||||
|
|
||||||
恢复后重点检查 `.env.production`、`static/guide-data/manifest.json` 和 `src/utils/publicUrl.ts`,确认正式环境仍指向 `172.20.14.21` 和 `https://guide.sznhmuseum.org.cn`。
|
恢复后重点检查 `.env.production`、`static/guide-data/manifest.json` 和 `src/utils/publicUrl.ts`,确认正式环境仍指向 `172.20.14.21` 和 `https://guide.sznhmuseum.org.cn`。
|
||||||
|
|
||||||
## Nginx 当前生产配置(2026-07-24)
|
## Nginx 与 CDN 当前生产配置(2026-07-28)
|
||||||
|
|
||||||
本节以 `172.20.14.21` 上 `docker exec sgs-nginx nginx -T` 的实际生效结果为准。主 Nginx 使用 Docker host 网络,公共域名不直接读取宿主静态目录,而是通过 upstream `sgs_mobile_pool` 转发到五台 `17083` 工作节点:
|
本节以 `172.20.14.21` 上 `docker exec sgs-nginx nginx -T` 的实际生效结果为准。主 Nginx 使用 Docker host 网络,公共域名不直接读取宿主静态目录,而是通过 upstream `sgs_mobile_pool` 转发到五台 `17083` 工作节点:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
guide.sznhmuseum.org.cn:80 -> sgs_mobile_pool -> 172.20.14.21/.23/.26/.27/.33:17083
|
游客 HTTPS -> guide.sznhmuseum.org.cn CDN -> guide-real.sznhmuseum.org.cn:443
|
||||||
guide.sznhmuseum.org.cn:443 -> sgs_mobile_pool -> 172.20.14.21/.23/.26/.27/.33:17083
|
-> 218.17.240.244 / 172.20.14.21 sgs-nginx
|
||||||
|
-> sgs_mobile_pool -> 172.20.14.21/.23/.26/.27/.33:17083
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`.21:/data/nginx/conf.d/guide-public.conf` 的 HTTP/HTTPS `server_name` 均包含 `guide.sznhmuseum.org.cn` 和 `guide-real.sznhmuseum.org.cn`。通配符证书 `*.sznhmuseum.org.cn` 覆盖两者,有效期至 2027-01-14。80 端口只保留 ACME challenge 直出和 `/_analytics/` 统一 404,其余请求 301 到正式 HTTPS 域名。游客 HTTP 到 HTTPS 的跳转仍应在 CDN 边缘启用;CDN 使用 HTTPS 回源时,不能依赖源站 80 端口完成游客侧跳转。
|
||||||
|
|
||||||
|
CDN 控制台应使用以下回源基线:
|
||||||
|
|
||||||
|
- 回源地址、Host 和 SNI:`guide-real.sznhmuseum.org.cn`;
|
||||||
|
- 回源协议/端口:HTTPS `443`;
|
||||||
|
- 启用源站证书校验;
|
||||||
|
- 游客域名始终为 `guide.sznhmuseum.org.cn`;
|
||||||
|
- 不把 `guide-real` 写入前端构建变量或对外链接。
|
||||||
|
|
||||||
当前移动端工作节点 `17083` 的关键规则如下:
|
当前移动端工作节点 `17083` 的关键规则如下:
|
||||||
|
|
||||||
```nginx
|
```nginx
|
||||||
@@ -130,48 +146,30 @@ server {
|
|||||||
try_files $uri =404;
|
try_files $uri =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
# 模型、manifest、GLB/GLTF 等:明确 MIME,缺失时返回 404
|
# 实际配置还按可变性拆分以下资源;变更时以 nginx -T 为准:
|
||||||
location ^~ /static/nav-assets/ {
|
# - index.html、SPA fallback、/engine/index.html、guide-data、固定名 SDK 入口:no-store
|
||||||
types {
|
# - engine chunks、字体、模型及普通静态文件:30 天
|
||||||
application/json json;
|
# - 缺失静态资源:404,且不附加长期缓存头
|
||||||
model/gltf-binary glb;
|
# - 页面路由:仅页面请求允许回退 /index.html,回退响应为 no-store
|
||||||
model/gltf+json gltf;
|
|
||||||
text/csv csv;
|
|
||||||
text/markdown md;
|
|
||||||
}
|
|
||||||
default_type application/octet-stream;
|
|
||||||
expires 30d;
|
|
||||||
add_header Cache-Control "public";
|
|
||||||
try_files $uri =404;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 字体:30 天缓存;其他 static 资源不得回退 index.html
|
|
||||||
location ^~ /static/Fonts/ {
|
|
||||||
add_header Cache-Control "public, max-age=2592000";
|
|
||||||
try_files $uri =404;
|
|
||||||
}
|
|
||||||
location ^~ /static/ {
|
|
||||||
try_files $uri =404;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 页面路由才允许 SPA fallback
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ /index.html;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
注意:
|
注意:
|
||||||
|
|
||||||
- `/assets/`、`/static/nav-assets/`、`/static/Fonts/` 和其他 `/static/` 路径必须优先 `try_files $uri =404`,不能把缺失的 JSON、GLB、字体返回为 `index.html`。
|
- `/assets/`、`/static/nav-assets/`、`/static/Fonts/` 和其他 `/static/` 路径必须优先 `try_files $uri =404`,不能把缺失的 JSON、GLB、字体返回为 `index.html`。
|
||||||
- `index.html` 仍应保持不缓存或短缓存;带 hash 的 `/assets/` 才使用长期不可变缓存。
|
- `index.html`、SPA fallback、`/engine/index.html`、`/static/guide-data/` 和固定文件名 SDK 入口必须为 `Cache-Control: no-store`;带 hash 的 `/assets/` 才使用一年不可变缓存。
|
||||||
- `guide-public.conf` 的 80/443 入口包含 ACME challenge 的直接静态规则,其余请求代理到 `sgs_mobile_pool`;不要把公共域名改回单节点静态 root。
|
- engine chunk、字体、模型和普通静态文件使用 30 天缓存;缺失资源返回 404,不能带长期缓存头。
|
||||||
|
- `guide-public.conf` 的 80/443 入口包含 ACME challenge 和 `/_analytics/` 404 规则;不要把公共域名改回单节点静态 root。
|
||||||
- 当前 upstream 使用 `least_conn`,单节点由 `max_fails=3 fail_timeout=10s` 被动摘除。
|
- 当前 upstream 使用 `least_conn`,单节点由 `max_fails=3 fail_timeout=10s` 被动摘除。
|
||||||
|
- 所有 `/_analytics/` 路径必须保持 404;不得恢复 Tracker、Matomo 注入、匿名访问通知、`visitor.js` 或 `privacy.html`。
|
||||||
|
|
||||||
2026-07-24 逐节点直连 `17083` 复核时发现配置漂移:`.21` 缓存策略正确,`.23/.26/.27/.33` 缺少 `/assets/` 长期 immutable 缓存头和 `/static/Fonts/` 专用规则。四台异常节点已分别备份配置、补齐对应 `17083` location,并在 `nginx -t` 通过后平滑 reload。修复后五台均满足:
|
2026-07-24 逐节点直连 `17083` 复核时发现配置漂移:`.21` 缓存策略正确,`.23/.26/.27/.33` 缺少 `/assets/` 长期 immutable 缓存头和 `/static/Fonts/` 专用规则。四台异常节点已分别备份配置、补齐对应 `17083` location,并在 `nginx -t` 通过后平滑 reload。2026-07-27 至 28 日又完成 CDN 分层缓存适配,并同步更新 `.21:/data/scripts/sync-frontend-nodes.sh` 的 `write_worker_conf()` 模板。当前五台均满足:
|
||||||
|
|
||||||
- 字体返回 `Cache-Control: public, max-age=2592000`;
|
- 字体返回 `Cache-Control: public, max-age=2592000`;
|
||||||
- 带 hash 的 assets 返回 `Cache-Control: public, max-age=31536000, immutable`;
|
- 带 hash 的 assets 返回 `Cache-Control: public, max-age=31536000, immutable`;
|
||||||
|
- HTML、SPA fallback、guide-data 和固定名 SDK 入口返回 `Cache-Control: no-store`;
|
||||||
|
- engine chunk、字体、模型及普通静态文件返回 30 天缓存;
|
||||||
|
- 缺失静态资源返回 HTTP `404` 且不附加长期缓存头;
|
||||||
- 字体 ETag 条件请求返回 HTTP `304`,且 `304` 响应仍保留 30 天缓存头;
|
- 字体 ETag 条件请求返回 HTTP `304`,且 `304` 响应仍保留 30 天缓存头;
|
||||||
- 20 个 `17080-17083 /healthz` 端点全部正常,五台 `sgs-nginx` 容器均未重启。
|
- 20 个 `17080-17083 /healthz` 端点全部正常,五台 `sgs-nginx` 容器均未重启。
|
||||||
|
|
||||||
@@ -342,15 +340,15 @@ $script | ssh -o StrictHostKeyChecking=no root@172.20.14.21 'bash -s'
|
|||||||
ssh -o StrictHostKeyChecking=no root@172.20.14.21 'bash /data/scripts/sync-frontend-nodes.sh'
|
ssh -o StrictHostKeyChecking=no root@172.20.14.21 'bash /data/scripts/sync-frontend-nodes.sh'
|
||||||
```
|
```
|
||||||
|
|
||||||
执行前必须注意:该脚本不仅同步 `/data/nginx/html`,还会通过 `write_worker_conf()` 重写五台工作节点的 `/data/nginx/conf.d/sgs-worker.conf`。2026-07-24 已修复 `.23/.26/.27/.33` 的 `17083` 缓存配置漂移,当前五台生效配置均包含 `/assets/` 一年 immutable 缓存、`/static/Fonts/` 30 天缓存以及静态资源 404 规则;但同步脚本文件本身仍需要单独复核,不能用脚本内容推断当前生产配置。**普通移动端静态发布不得在未复核脚本内嵌配置前直接运行该脚本。**
|
执行前必须注意:该脚本不仅同步 `/data/nginx/html`,还会通过 `write_worker_conf()` 重写五台工作节点的 `/data/nginx/conf.d/sgs-worker.conf`。脚本模板已于 2026-07-28 同步当前 `17083` CDN 分层缓存策略,但每次使用前仍必须复核脚本与现网配置。**普通移动端静态发布不得在未复核脚本内嵌配置前直接运行该脚本。**
|
||||||
|
|
||||||
继续使用同步脚本前先检查它是否已经包含本次规则:
|
继续使用同步脚本前先检查它是否已经包含本次规则:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
ssh -o StrictHostKeyChecking=no root@172.20.14.21 'grep -n -E "static/Fonts|31536000|try_files \\$uri =404" /data/scripts/sync-frontend-nodes.sh'
|
ssh -o StrictHostKeyChecking=no root@172.20.14.21 'grep -n -E "no-store|static/guide-data|engine/index.html|31536000|2592000|try_files \\$uri =404" /data/scripts/sync-frontend-nodes.sh'
|
||||||
```
|
```
|
||||||
|
|
||||||
如果检查没有同时看到 `static/Fonts` 和 `31536000`,应先在维护窗口审核并更新 `write_worker_conf()`,再执行 `bash -n /data/scripts/sync-frontend-nodes.sh`、逐节点 `nginx -t` 和 `/healthz` 验证。不要用 `.21` 的整份 `sgs-worker.conf` 覆盖其他节点,因为 `.21` 的 `17080` 还包含本节点专用 CSP 配置;只同步审核后的 `17083` 移动端配置块。
|
如果检查未同时覆盖 no-store、30 天缓存、一年 immutable 和静态 404 规则,应先在维护窗口审核并更新 `write_worker_conf()`,再执行 `bash -n /data/scripts/sync-frontend-nodes.sh`、逐节点 `nginx -t` 和 `/healthz` 验证。不要用 `.21` 的整份 `sgs-worker.conf` 覆盖其他节点,因为 `.21` 的 `17080` 还包含本节点专用 CSP 配置;只同步审核后的 `17083` 移动端配置块。
|
||||||
|
|
||||||
如果本次仅发布 H5 静态文件、没有修改 Nginx 配置,推荐采用“仅同步 `/data/nginx/html/mobile`”的流程,不要触发同步脚本中的 `write_worker_conf()`、`/data/apps/sgs-map` 同步和 PM2 重启。静态文件替换完成后不需要 Nginx reload;只有配置变更才执行 `nginx -t` 后 reload。
|
如果本次仅发布 H5 静态文件、没有修改 Nginx 配置,推荐采用“仅同步 `/data/nginx/html/mobile`”的流程,不要触发同步脚本中的 `write_worker_conf()`、`/data/apps/sgs-map` 同步和 PM2 重启。静态文件替换完成后不需要 Nginx reload;只有配置变更才执行 `nginx -t` 后 reload。
|
||||||
|
|
||||||
@@ -413,6 +411,37 @@ foreach ($node in $nodes) {
|
|||||||
|
|
||||||
此流程不修改 `/data/nginx/conf.d`,不执行 `nginx -s reload`,也不操作 `/data/apps/sgs-map` 或 PM2。只有 Nginx 配置变更才需要先 `nginx -t` 再 reload。
|
此流程不修改 `/data/nginx/conf.d`,不执行 `nginx -s reload`,也不操作 `/data/apps/sgs-map` 或 PM2。只有 Nginx 配置变更才需要先 `nginx -t` 再 reload。
|
||||||
|
|
||||||
|
## 讲解音频与 CDN 兼容
|
||||||
|
|
||||||
|
### 当前链路
|
||||||
|
|
||||||
|
讲解音频的正确生产链路为:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/app-api/gis/guide/stop/info 或 /app-api/gis/guide/audio/play-info
|
||||||
|
-> 返回 https://guide.sznhmuseum.org.cn/minio/museum-assets/...mp3
|
||||||
|
-> CDN
|
||||||
|
-> .21 /minio/ 代理
|
||||||
|
-> sgs_minio / museum-assets 对象
|
||||||
|
```
|
||||||
|
|
||||||
|
`.21:/data/nginx/conf.d/guide-public.conf` 当前还保留以下兼容措施:
|
||||||
|
|
||||||
|
- `/app-api/gis/sdk/minio/museum-assets/` 直接代理到 `sgs_minio/museum-assets/`,绕过会返回拒绝访问 HTML 的 Java SDK 媒体代理;
|
||||||
|
- 对 `/app-api/gis/guide/stop/info` 和 `/app-api/gis/guide/audio/play-info` 精确启用 no-store 响应改写,将相对 `/minio/museum-assets/...` 地址改为正式域名绝对 URL;
|
||||||
|
- `/minio/museum-assets/tts-audio/audio/` 保留 Range 请求能力,正常响应应为 `audio/mpeg` 和 HTTP `206`。
|
||||||
|
|
||||||
|
上述 Nginx 兼容层属于生产止血措施。长期方案应在以下两项中择一实施并完成回归测试:
|
||||||
|
|
||||||
|
1. 前端修正 `src/utils/publicUrl.ts`,不再把 `/minio/` 强制转换为 `/app-api/gis/sdk/minio/`;
|
||||||
|
2. Java SDK 媒体代理修复权限、状态码、Content-Type 和 Range 转发。
|
||||||
|
|
||||||
|
在长期方案上线、CDN 污染对象完成清理且原 SDK 媒体 URL 验证正常前,不得删除当前兼容路由或 API URL 改写。
|
||||||
|
|
||||||
|
### 故障识别
|
||||||
|
|
||||||
|
已确认的错误特征为:请求 MP3 时收到 HTTP `206`,但 `Content-Type` 为 `text/html;charset=utf-8`、响应约 726 字节,正文提示页面被管理员禁止。该响应来自 Java SDK 媒体代理的拒绝访问页;CDN 曾缓存该错误对象。只看 HTTP 状态码会误判成功,音频验收必须同时检查 MIME、Range、长度和文件头。
|
||||||
|
|
||||||
## 线上验证
|
## 线上验证
|
||||||
|
|
||||||
公网验证:
|
公网验证:
|
||||||
@@ -437,9 +466,10 @@ curl.exe -sI "$base/static/__not_exists__.json" | Select-String 'HTTP/|Content-T
|
|||||||
预期:
|
预期:
|
||||||
|
|
||||||
- `/assets/<hash>.js`:HTTP `200`,`Cache-Control` 含 `max-age=31536000, immutable`;
|
- `/assets/<hash>.js`:HTTP `200`,`Cache-Control` 含 `max-age=31536000, immutable`;
|
||||||
|
- `/`、`/index.html`、`/engine/index.html` 和 `/static/guide-data/*.json`:HTTP `200`,`Cache-Control` 为 no-store;
|
||||||
- manifest:HTTP `200`,`Content-Type: application/json`;
|
- manifest:HTTP `200`,`Content-Type: application/json`;
|
||||||
- 真实 GLB:HTTP `200`,`Content-Type: model/gltf-binary`;
|
- 真实 GLB:HTTP `200`,`Content-Type: model/gltf-binary`;
|
||||||
- `/static/__not_exists__.json`:HTTP `404`,不得返回 `200 text/html`。
|
- `/static/__not_exists__.json`:HTTP `404`,不得返回 `200 text/html`,也不得附加长期缓存头。
|
||||||
|
|
||||||
入口 JS 验证:
|
入口 JS 验证:
|
||||||
|
|
||||||
@@ -513,6 +543,62 @@ foreach ($node in $nodes) {
|
|||||||
|
|
||||||
注意:`.21` 的整份 `sgs-worker.conf` 哈希可以与其余节点不同,因为它还承载额外的 `17080` CSP 配置;验收目标是五台 `17083` 移动端配置块和响应行为一致。不要用 `.21` 的整份配置覆盖其他节点。
|
注意:`.21` 的整份 `sgs-worker.conf` 哈希可以与其余节点不同,因为它还承载额外的 `17080` CSP 配置;验收目标是五台 `17083` 移动端配置块和响应行为一致。不要用 `.21` 的整份配置覆盖其他节点。
|
||||||
|
|
||||||
|
### 源站、音频与安全负向验证
|
||||||
|
|
||||||
|
使用 `--resolve` 绕过 CDN 直连源站,确认 Host/SNI、入口缓存和音频 Range 行为:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$origin = '218.17.240.244'
|
||||||
|
$originHost = 'guide-real.sznhmuseum.org.cn'
|
||||||
|
$public = 'https://guide.sznhmuseum.org.cn'
|
||||||
|
$audio = '/minio/museum-assets/tts-audio/audio/2026/07/17/cdb263222e7749009db1768b49477283.mp3'
|
||||||
|
|
||||||
|
curl.exe --resolve "${originHost}:443:${origin}" -sI "https://${originHost}/"
|
||||||
|
curl.exe --resolve "${originHost}:443:${origin}" -sI "https://${originHost}/engine/index.html"
|
||||||
|
curl.exe --resolve "${originHost}:443:${origin}" -sI "https://${originHost}/static/guide-data/manifest.json"
|
||||||
|
curl.exe --resolve "${originHost}:443:${origin}" -sS -D - -o NUL -H 'Range: bytes=0-31' "https://${originHost}${audio}"
|
||||||
|
curl.exe -sS -D - -o NUL -H 'Range: bytes=0-31' "${public}${audio}"
|
||||||
|
```
|
||||||
|
|
||||||
|
音频源站和 CDN 响应均应满足:HTTP `206`、`Content-Type: audio/mpeg`、有效 `Content-Range`,且不得出现约 726 字节的 `text/html`。随后在 390 x 844 移动浏览器中打开英文展项 `865546638960193536`,确认播放器时间从 `0:00` 推进、可完整播放并正常结束。
|
||||||
|
|
||||||
|
安全负向检查:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
@('/_analytics/visitor.js','/_analytics/privacy.html','/_analytics/matomo.js','/_analytics/matomo.php') |
|
||||||
|
ForEach-Object { curl.exe -s -o NUL -w "%{http_code} $_`n" "$public$_" }
|
||||||
|
```
|
||||||
|
|
||||||
|
四项必须全部返回 HTTP `404`。
|
||||||
|
|
||||||
|
### CDN 控制台发布后检查
|
||||||
|
|
||||||
|
CDN 控制台操作不能由源站部署脚本代替。每次部署涉及 HTML、guide-data、engine 固定入口或音频路由时,至少刷新:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://guide.sznhmuseum.org.cn/
|
||||||
|
https://guide.sznhmuseum.org.cn/index.html
|
||||||
|
https://guide.sznhmuseum.org.cn/engine/index.html
|
||||||
|
https://guide.sznhmuseum.org.cn/static/guide-data/
|
||||||
|
```
|
||||||
|
|
||||||
|
若处理过讲解音频代理,还需刷新:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://guide.sznhmuseum.org.cn/app-api/gis/sdk/minio/museum-assets/
|
||||||
|
```
|
||||||
|
|
||||||
|
CDN 规则应保持:
|
||||||
|
|
||||||
|
- `/assets/*`:遵循源站一年 immutable;
|
||||||
|
- `/minio/museum-assets/tts-audio/audio/*`:30 天;仅在确认文件名内容不可变时才可提升为一年 immutable;
|
||||||
|
- `/app-api/gis/guide/audio/*`、`/app-api/gis/guide/stop/*`:TTL 0;
|
||||||
|
- `/app-api/gis/sdk/minio/museum-assets/*`:污染对象清理和直源验证完成前 TTL 0;
|
||||||
|
- HTML、SPA fallback、`/engine/index.html`、guide-data 和固定名 SDK 入口:TTL 0 或严格遵循源站 no-store;
|
||||||
|
- 媒体缓存必须校验成功状态和正确 Content-Type,禁止把 `text/html` 当作音频缓存。
|
||||||
|
|
||||||
|
同时在 CDN 边缘启用游客 HTTP 到 HTTPS 的 301。控制台变更后重新执行公网与 `--resolve` 对照检查,以区分 CDN 和源站响应。
|
||||||
|
|
||||||
## 回滚
|
## 回滚
|
||||||
|
|
||||||
主节点部署脚本会在 `/data/nginx/html/_backups` 下生成备份,例如:
|
主节点部署脚本会在 `/data/nginx/html/_backups` 下生成备份,例如:
|
||||||
@@ -540,6 +626,14 @@ $script | ssh -o StrictHostKeyChecking=no root@172.20.14.21 'bash -s'
|
|||||||
|
|
||||||
回滚后应使用前述“仅同步 mobile 静态目录”流程把回滚版本同步到四个工作节点,并重新验证五节点入口 JS 的 SHA256。只有已确认 `/data/scripts/sync-frontend-nodes.sh` 内嵌 Nginx 配置与生产一致时,才允许用全量脚本同步。
|
回滚后应使用前述“仅同步 mobile 静态目录”流程把回滚版本同步到四个工作节点,并重新验证五节点入口 JS 的 SHA256。只有已确认 `/data/scripts/sync-frontend-nodes.sh` 内嵌 Nginx 配置与生产一致时,才允许用全量脚本同步。
|
||||||
|
|
||||||
|
如需回滚 CDN/Nginx 适配,使用对应变更备份,不能用旧整目录覆盖现网:
|
||||||
|
|
||||||
|
- CDN 源站集群适配:`/data/nginx/_backups/cdn-origin-cluster-20260727223921`;
|
||||||
|
- SDK MinIO 音频绕过:`/data/nginx/_backups/audio-sdk-minio-bypass-20260727232518`;
|
||||||
|
- 音频 API URL 改写:`/data/nginx/_backups/audio-api-url-rewrite-20260727233006`。
|
||||||
|
|
||||||
|
回滚顺序固定为:确认影响范围,备份当前配置,只恢复对应文件或 location,逐节点执行 `docker exec sgs-nginx nginx -t`,平滑 reload,再验证五节点 `/healthz`、正式域名、源站域名、音频 Range 和 `/_analytics/` 404。若 CDN 已缓存回滚前对象,还需在控制台刷新对应 URL;仅回滚源站不会自动清除 CDN 对象。
|
||||||
|
|
||||||
## 已遇到的问题与处理
|
## 已遇到的问题与处理
|
||||||
|
|
||||||
### 1. terser 压缩阶段内存不足
|
### 1. terser 压缩阶段内存不足
|
||||||
@@ -643,7 +737,30 @@ current: { node: 'v20.19.5', npm: '10.8.2' }
|
|||||||
- 验收时关注最终 PM2 状态是否 `online`。
|
- 验收时关注最终 PM2 状态是否 `online`。
|
||||||
- 如未来只需同步 mobile,可拆分或新增专用同步脚本,避免不必要地重启 map 服务。
|
- 如未来只需同步 mobile,可拆分或新增专用同步脚本,避免不必要地重启 map 服务。
|
||||||
|
|
||||||
### 8. 页面返回 200 但浏览器空白
|
### 8. CDN 后讲解音频返回 HTML
|
||||||
|
|
||||||
|
现象:
|
||||||
|
|
||||||
|
```text
|
||||||
|
HTTP 206
|
||||||
|
Content-Type: text/html;charset=utf-8
|
||||||
|
Content-Length: 726
|
||||||
|
```
|
||||||
|
|
||||||
|
根因:
|
||||||
|
|
||||||
|
- 前端把 `/minio/...mp3` 转换成 `/app-api/gis/sdk/minio/...mp3`;
|
||||||
|
- Java SDK 媒体代理返回拒绝访问 HTML,但状态仍为 200;
|
||||||
|
- CDN 缓存后以 206 响应 Range 请求,造成播放器无法解码。
|
||||||
|
|
||||||
|
处理:
|
||||||
|
|
||||||
|
- `.21` 兼容路由将 `/app-api/gis/sdk/minio/museum-assets/` 直接代理到 MinIO;
|
||||||
|
- 两个讲解 API 的响应 URL 改写为正式域名 `/minio/museum-assets/...`;
|
||||||
|
- CDN 清除污染前,SDK media 路径 TTL 设为 0;
|
||||||
|
- 验收同时检查状态、`audio/mpeg`、`Content-Range`、文件头和浏览器播放进度。
|
||||||
|
|
||||||
|
### 9. 页面返回 200 但浏览器空白
|
||||||
|
|
||||||
现象:
|
现象:
|
||||||
|
|
||||||
@@ -679,3 +796,6 @@ https://guide.sznhmuseum.org.cn/ HTTP 200
|
|||||||
- 2026-07-20:拉取远程最新代码前已执行 `git stash push -u -m pre-deploy-prod-local-fixes-20260720232941`,确认“本地补丁已 stash”;随后快进到 `735c5cd`,执行 `git stash pop` 恢复正式环境补丁,无冲突。构建入口为 `assets/index-CsFOrYfU.js`,主节点备份为 `/data/nginx/html/_backups/mobile-before-deploy-20260720233343.tar.gz`,同步脚本最终输出 `All frontend worker nodes synced.`。
|
- 2026-07-20:拉取远程最新代码前已执行 `git stash push -u -m pre-deploy-prod-local-fixes-20260720232941`,确认“本地补丁已 stash”;随后快进到 `735c5cd`,执行 `git stash pop` 恢复正式环境补丁,无冲突。构建入口为 `assets/index-CsFOrYfU.js`,主节点备份为 `/data/nginx/html/_backups/mobile-before-deploy-20260720233343.tar.gz`,同步脚本最终输出 `All frontend worker nodes synced.`。
|
||||||
- 2026-07-23:移动端 `17083` 目标配置新增 `/assets/` 一年 immutable 缓存、`/static/Fonts/` 30 天缓存、`/static/nav-assets/` MIME/30 天缓存及全部 `/static/` 缺失资源返回 404。普通 H5 发布改为优先仅同步 mobile 静态目录,不再无条件重写 `sgs-worker.conf`、同步地图应用或重启 PM2。
|
- 2026-07-23:移动端 `17083` 目标配置新增 `/assets/` 一年 immutable 缓存、`/static/Fonts/` 30 天缓存、`/static/nav-assets/` MIME/30 天缓存及全部 `/static/` 缺失资源返回 404。普通 H5 发布改为优先仅同步 mobile 静态目录,不再无条件重写 `sgs-worker.conf`、同步地图应用或重启 PM2。
|
||||||
- 2026-07-24:逐节点直连复核发现 `.23/.26/.27/.33` 存在 `17083` 缓存配置漂移,仅 `.21` 正确;四台异常节点已分别备份并补齐字体和 hash assets 缓存规则,`nginx -t` 后平滑 reload。修复后字体缓存头、hash asset immutable 缓存头及字体 ETag/304 均为 5/5 一致,20 个工作端点和六类对外入口正常,五台 Nginx 容器均未重启。部署验收新增五节点直连缓存头与 ETag/304 检查,避免公网 `least_conn` 抽样漏检单节点漂移。
|
- 2026-07-24:逐节点直连复核发现 `.23/.26/.27/.33` 存在 `17083` 缓存配置漂移,仅 `.21` 正确;四台异常节点已分别备份并补齐字体和 hash assets 缓存规则,`nginx -t` 后平滑 reload。修复后字体缓存头、hash asset immutable 缓存头及字体 ETag/304 均为 5/5 一致,20 个工作端点和六类对外入口正常,五台 Nginx 容器均未重启。部署验收新增五节点直连缓存头与 ETag/304 检查,避免公网 `least_conn` 抽样漏检单节点漂移。
|
||||||
|
- 2026-07-27:从分支 `codex/import-sgs-frontend-mobile-20260727` 部署提交 `f1047414bbf00a254e1c0cf99755556e45a18e6f`,生产入口 `assets/index-DvpqYP-p.js`,SHA256 `b9f099e2d30d71ca691cc64f20ca6808af834b12dce1c9af8838a6aef1eb893d`;五节点一致,`/engine/` 运行时和移动端导览/讲解流程验证通过。
|
||||||
|
- 2026-07-27 至 28 日:新增 `guide-real.sznhmuseum.org.cn` CDN 源站域名并完成五节点 `17083` 分层缓存适配;同步脚本模板已更新。随后修复 CDN 后英文讲解音频失败:绕过错误 Java SDK 媒体代理,并把讲解 API 的 `/minio/` URL 改写为正式域名绝对路径。五组语言/声线音频均验证为 HTTP 206、`audio/mpeg` 和正确 MPEG 文件头,展项 `865546638960193536` 英文音频可完整播放至 48.96 秒。CDN 控制台刷新、边缘 HTTP 到 HTTPS 和 Host/SNI 规则仍需按本文清单人工维护。
|
||||||
|
- 2026-07-28:目标分支已快进同步到 `fc93b8d7d32a208a037be576ce3b9da2db3c1fe3`,包含讲解列表、宿主环境判断、展厅卡片图片及相关测试更新。本条只记录文档编制时的代码基线;生产仍以最近一次明确部署记录 `f1047414bbf00a254e1c0cf99755556e45a18e6f` 为准,后续上线 `fc93b8d` 时必须另行补充构建产物、五节点哈希和验收记录。
|
||||||
|
|||||||
Reference in New Issue
Block a user