chore(douyin-mashida): 公网联调工具链(切地址 + 前置自检)

真实联调必须让平台能主动推到本机,所以需要隧道;这两个脚本把「配置切换」和
「联调前该验的东西」自动化,避免手工漏配(尤其 certLink 漏改、占位密钥没换):

- `douyin-mashida:set-public-url`:把 certLink/afterVerifyLink 切成隧道地址,
  打印平台侧要配的三项(message_url / topics / 卡券链接),并自检隧道:
  用错误签名打公网地址,期望 401 —— 证明「隧道 → Caddy → 后端 → 验签」通了,
  不需要密钥、也不产生真实订单
- `douyin-mashida:preflight`:四步自检
  ① 配置就绪度(含识别早期联调留下的占位密钥,它会让 hasSecret=true 骗过你)
  ② 真实网关连通性:平台是先校 uid 再校签名,带 --secret 时若平台报的不是
     签名错误即证明签名/密钥正确(正式推送前就能排掉密钥问题)
  ③ 公网回调可达性 ④ certLink 与公网域名是否一致
- 平台文档只给了 code=10000 表示成功,无完整错误码表,故脚本不翻译码值、
  只原样打印,并对实测观测到的码(如 10014)加说明

同时修掉 vite dev server 的一个潜在坑:`VITE_ALLOWED_HOSTS` 早已在 .env 与
compose 中配置,但 vite.config.ts 的白名单是硬编码的、从未读取该变量,
换隧道域名必然被 Vite 拦(Blocked request);现已真正接上并默认放行
常见隧道域名后缀。
This commit is contained in:
yml2213
2026-10-09 12:01:42 +08:00
parent 8c33ff62ec
commit e9a87194bd
4 changed files with 782 additions and 1 deletions
+29 -1
View File
@@ -7,6 +7,34 @@ import { defineConfig } from 'vite'
const currentDir = path.dirname(fileURLToPath(import.meta.url))
const apiTarget = process.env.VITE_API_TARGET || 'http://127.0.0.1'
/**
* dev server 的 Host 白名单。
*
* 用隧道(ngrok / cloudflared)做公网联调时,请求经隧道打到 Caddy、再转发到本 dev server,
* Host 头是**隧道域名**;不在白名单里 Vite 会直接拒绝
* ("Blocked request. This host is not allowed."),表现为页面打不开、后端日志却一片正常。
*
* 所以:常见隧道域名后缀默认放行,`VITE_ALLOWED_HOSTS`(compose 里已透传)可再追加,
* 逗号分隔、允许 `.example.com` 这种后缀写法。只影响 dev server,不影响构建产物。
*/
const tunnelHosts = ['.ngrok-free.app', '.ngrok.app', '.ngrok.io', '.trycloudflare.com']
const extraAllowedHosts = (process.env.VITE_ALLOWED_HOSTS || '')
.split(',')
.map((host) => host.trim())
.filter(Boolean)
const allowedHosts = [
...new Set([
'localhost',
'.localhost',
'127.0.0.1',
'221329.cc.cd',
'.cc.cd',
...tunnelHosts,
...extraAllowedHosts,
]),
]
export default defineConfig({
plugins: [react()],
resolve: {
@@ -18,7 +46,7 @@ export default defineConfig({
host: '0.0.0.0',
port: 5173,
// 隧道/自定义域名访问 dev server 时需加入白名单,否则 Vite 会拦截 Host
allowedHosts: ['localhost', '.localhost', '127.0.0.1', '221329.cc.cd', '.cc.cd'],
allowedHosts,
proxy: {
'/api': {
target: apiTarget,