Files
gongxue-base/docs/refactor/taro-h5-deployment.md
2026-07-01 02:37:43 +08:00

235 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Taro H5 三入口部署说明
更新时间2026-07-01
当前 `apps/taro` 采用一个 Taro 4 React 工程、三套 H5 产物的方式交付:
- 学生学习端:刷题、背单词、知识手册、分数线、资料、会员、个人中心。
- 租户后台品牌、主题、域名、题库、导入、学生、订单、营销、销售、CRM、财务和数据看板。
- 平台后台租户、SaaS 套餐、订阅账单、公共题库授权和平台审计。
后续微信小程序仍复用同一套业务 services 和页面逻辑,但 H5 是当前优先上线形态。
## 构建命令
```bash
npm run build:taro:h5:student
npm run build:taro:h5:tenant
npm run build:taro:h5:platform
```
输出目录:
```text
apps/taro/dist/h5-student
apps/taro/dist/h5-tenant-admin
apps/taro/dist/h5-platform-admin
```
注意Taro H5 入口依赖 `apps/taro/src/index.html` 模板生成 `index.html`。如果构建产物目录里只有 `js/css/assets` 而没有 `index.html`,不要发布;重新构建并运行发布守卫脚本。
推荐部署:
| 域名 | 静态目录 | 说明 |
| --- | --- | --- |
| `www.example.com` 或租户自有学生端域名 | `h5-student` | 面向学生和 C 端用户 |
| `admin.example.com` | `h5-tenant-admin` | 面向租户公司运营、教师、销售、代理、管理员 |
| `console.example.com` | `h5-platform-admin` | 面向平台超级管理员 |
三个入口可以放在同一台服务器的三个静态目录,也可以分别放到不同服务器或 CDN/对象存储静态网站。API 推荐独立域名,例如 `api.example.com`
## 运行时配置
H5 产物支持运行时覆盖公开配置。每个静态目录根部放一个 `runtime-config.json`
```text
/www/tiku/h5-student/runtime-config.json
/www/tiku/h5-tenant-admin/runtime-config.json
/www/tiku/h5-platform-admin/runtime-config.json
```
示例文件:
```text
apps/taro/deploy/h5-student.runtime-config.example.json
apps/taro/deploy/h5-tenant-admin.runtime-config.example.json
apps/taro/deploy/h5-platform-admin.runtime-config.example.json
```
生产示例:
```json
{
"portal": "student",
"apiBaseUrl": "https://api.example.com",
"supabaseUrl": "https://auth.example.com",
"supabasePublishableKey": "replace-with-supabase-publishable-key",
"tenantCode": ""
}
```
允许字段:
```text
portal student | tenant-admin | platform-admin
apiBaseUrl apps/api 公开 HTTPS 地址
supabaseUrl Supabase Auth/API 公开 HTTPS 地址
supabasePublishableKey Supabase publishable/anon key
tenantCode 小程序、预览环境或指定租户部署可用
```
这些字段是前端公开配置,不是密钥。`apps/taro/src/env.ts` 会拒绝 `runtime-config.json` 中出现服务端密钥类字段,例如:
```text
SUPABASE_SERVICE_ROLE_KEY
SUPABASE_SECRET_KEY
DATABASE_URL
ALIYUN_OSS_ACCESS_KEY_SECRET
TENCENT_COS_SECRET_KEY
WECHAT_PAY_PRIVATE_KEY
ALIPAY_APP_PRIVATE_KEY
AUTH_SESSION_SECRET
PLATFORM_ADMIN_API_KEY
```
构建时仍可以设置同名 `TARO_APP_*` 变量作为默认值,但生产更推荐用 `runtime-config.json`。这样 API 域名、Auth 域名、租户预览码变化时不需要重新构建 H5。
## Nginx 示例
H5 使用 browser history 路由时,静态服务器需要把未知路径回退到 `index.html`。同时对 `runtime-config.json` 禁用缓存,对 hash 后的 JS/CSS 长缓存。
```nginx
server {
listen 443 ssl http2;
server_name www.example.com;
root /www/tiku/h5-student;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https: blob:; font-src 'self' data:; connect-src 'self' https://api.example.com https://auth.example.com; media-src 'self' https: blob:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" always;
location = /runtime-config.json {
add_header Cache-Control "no-store" always;
try_files $uri =404;
}
location ~* \.(?:js|css|woff2?|png|jpg|jpeg|gif|svg)$ {
add_header Cache-Control "public, max-age=31536000, immutable" always;
try_files $uri =404;
}
location / {
try_files $uri $uri/ /index.html;
}
}
```
租户后台和平台后台复用同样规则,替换 `server_name``root` 和 CSP 中的 `connect-src` 域名即可。若学生端需要打开 OSS/COS/CDN 签名资源,`img-src/media-src` 可加入对应 HTTPS 域名;不要加入通配符 `*`
## CORS 和 Cookie
API 的生产 `CORS_ORIGIN` 必须只包含实际前端域名:
```text
CORS_ORIGIN=https://www.example.com,https://admin.example.com,https://console.example.com
```
禁止生产环境使用:
```text
CORS_ORIGIN=*
```
当前前端以 `Authorization: Bearer <supabase_access_token 或 tk_session>` 调用 API`x-tenant-id` 只作为租户上下文,不作为身份来源。生产建议:
```text
ALLOW_LEGACY_AUTH_HEADERS=false
ALLOW_PLATFORM_ADMIN_KEY=false
```
H5 正式回归时建议把前端登录态切到 Supabase Auth并观察业务接口请求是否都发送 `Bearer <supabase_access_token>``tk_` session 只作为迁移/本地兜底,不应成为线上长期依赖。
## 前端请求边界
- 所有页面统一通过 `apps/taro/src/services/api.ts` 调用后端。
- 默认请求模式是 `authMode='auto'`H5 先用 Supabase JWT没有 JWT 才兜底迁移期 `tk_` session。
- 公共接口、短信登录、租户解析必须显式 `authMode='none'`;平台全局或租户解析不应带租户上下文时必须显式 `tenantId: null`
- H5 可以用 Supabase client 管理 Auth session/JWT但业务数据默认走 `apps/api`
- 页面代码不能通过 `headers` 覆盖 `Authorization``x-tenant-id`,身份和租户上下文只能走统一 client 的 token provider、`authMode``tenantId` 参数。
- 订单、支付、权益、内容导入、后台配置、CRM、对象存储签名、视频播放签名必须走后端命令层。
- 登录后禁止传 `x-user-id` 或 body/query `userId` 表示当前用户。
- 私有 PDF、图片、视频不能由前端拼接 URL必须使用 `content_assets` 和后端短签名。
## 发布步骤
1. 在新服务器或 CI 环境构建三套 H5
```bash
npm ci
npm run build:taro:h5:student
npm run build:taro:h5:tenant
npm run build:taro:h5:platform
```
2. 拷贝静态产物到对应 Web 根目录。
3. 根据示例文件创建每个目录的 `runtime-config.json`。
4. 配置 Nginx history fallback、缓存策略、安全响应头和 HTTPS。
5. 配置 API 的 `CORS_ORIGIN`、Supabase Auth 回调域名、微信/QQ/支付宝/微信支付回调域名。
6. 运行生产就绪检查:
```bash
npm run readiness:production
npm run readiness:production:db
npm run check:taro
```
构建后再运行 H5 发布守卫脚本:
```bash
npm run smoke:taro:h5
npm run smoke:taro:h5:interaction
node scripts/taro-h5-release-guardrails-test.js --require-dist
```
`smoke:taro:h5` 会用临时静态服务器检查三套 H5 产物可托管、资源可加载、history fallback 可用,并用 mock API 验证租户解析契约。`smoke:taro:h5:interaction` 会用真实 Chrome/Edge 打开三套发布产物并点击学生刷题/收藏/会员、租户题库内容/财务、平台租户/账务中心关键路径;若服务器没有默认浏览器,可设置 `TARO_H5_SMOKE_BROWSER=/path/to/chrome`。发布守卫会检查三套 H5 产物是否存在 `index.html`,源码和产物是否混入 `x-user-id`、`x-platform-admin-key`、PocketBase 引用、数据库连接串、服务端密钥形态,并检查运行时配置示例只包含公开字段。若还没有把真实 `runtime-config.json` 放入静态目录,会显示 warning正式发布前必须在每个 H5 目录根部补齐该文件。
写入 `production-launch-evidence.json` 的正式证据必须使用严格模式,确保三套发布目录都已放置真实公开 `runtime-config.json` 且没有 warning
```bash
npm --silent run smoke:taro:h5 -- --json > docs/refactor/launch-artifacts/taro-h5-static-smoke.json
npm --silent run smoke:taro:h5:interaction -- --json > docs/refactor/launch-artifacts/taro-h5-interaction-smoke.json
node scripts/taro-h5-release-guardrails-test.js --require-dist --require-runtime-config --json > docs/refactor/launch-artifacts/taro-h5-release-guardrails.json
```
7. 收集生产上线证据并运行 launch gate
```bash
cp docs/refactor/production-launch-evidence.template.json docs/refactor/production-launch-evidence.json
npm run launch:gate -- --evidence docs/refactor/production-launch-evidence.json
```
证据文件只保存命令摘要、artifact 路径、审批人和时间,不保存真实 access token、支付密钥、对象存储密钥或用户隐私明细。真实 artifact 建议放在 `docs/refactor/launch-artifacts/`,该目录不入 Git。
8. 打开三个域名,确认 `index.html` 正常加载,启动页能解析租户,登录后接口请求使用 `Authorization` 和正确的 `x-tenant-id`。
## 安全审计边界
H5 线上只发布 `apps/taro/dist/**` 静态文件和每个目录自己的 `runtime-config.json`,不要把 `apps/taro/node_modules`、源码目录、`.env`、部署脚本缓存放进 Web 根目录。
后端/API/worker 的生产依赖审计使用:
```bash
npm run audit:runtime
```
Taro 4.2.0 当前构建工具链仍可能触发 `npm run audit:taro:toolchain` 的上游 high/critical 告警,主要来自构建期 CLI、webpack、swiper、lodash-es 等传递依赖。不要使用 `npm audit fix --force` 将 Taro 降级到 3.x应等 Taro 官方升级后再处理,或后续评估 Vite runner 替代方案。上线时以静态产物、前端密钥检查、CORS 域名白名单、CSP 和 API runtime audit 作为阻断项。
## 小程序后续兼容
当前 `runtime-config.json` 只用于 H5。微信小程序版本应通过编译变量、小程序启动参数或后台小程序配置传入 `tenantCode`,再调用 `GET /api/tenant/resolve?tenantCode=...`。小程序端如 `supabase-js` 兼容性不稳定,保留 `apps/api/auth/*` 登录适配层H5 继续使用 Supabase client 管理 Auth。