实现 Pingora 发行网关路由并关闭两处路由漂移待办
Project CI / AI game creator shell Rust crates (push) Failing after 1m17s
Project CI / AI game creator shell Rust smoke (push) Successful in 2m1s
Project CI / AI game creator shell Rust lane 2/2 (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled

- 新增 RouteDecision::ReleaseGateway:/games/game_<32 位小写十六进制 id>/… 重写上游路径到 /api/game-distribution/releases/<gameId><asset>、清空 Cookie、不进 SPA fallback、不套接流保护分组、不受维护闸拦截,与 nginx 同名 location 同口径(只认小写 32 位十六进制)
- 路由矩阵新增 games_release_gateway 用例(含 upstreamPath 期望值)与对应断言;parity 门禁支持 release_gateway 并把 games_spa_fallback、games_release_gateway 列入必查清单
- check:pingora-gateway-smoke 新增三条运行时断言:重写到发行网关且上游拿不到 Cookie、/games/detail 仍走 SPA、/games/game/index.html 仍是真实 404
- 文档:Pingora 试点文档补「平台同源发行入口」语义;pitfalls 记录 SPA allowlist 三处真相源与「发行入口不是 SPA」;按 docs/project-memory/README.md 删除两份已关闭待办,关闭记录写入开放事项索引第五节
- 验证:网关 39 passed、check:pingora-route-parity OK(23 路由)、check:nginx-spa-routes OK(12 路由 / 3 模板)、check:pingora-gateway-smoke 通过、cargo fmt --all --check、check:production-ops、encoding / doc-index / diff 检查全绿;变异验证:矩阵 upstreamPath 写错或拿掉 /games/detail 都会立刻变红
This commit is contained in:
kdletters
2026-09-29 07:24:52 +08:00
parent 16ff10111f
commit 5fee115f10
9 changed files with 202 additions and 84 deletions
+49
View File
@@ -1011,6 +1011,55 @@ async function runSmokeCases(
`API 上游 X-Real-IP 未使用 TCP 对端 IP:${apiPayload.realIp}`,
);
// 平台同源发行入口:/games/game_<32 位小写十六进制 id>/… 重写到发行网关并清空 Cookie,
// 形状不符的路径不许被吞进发行网关(SPA 深链仍是 SPA,`/games/game/...` 仍是真实 404)。
const releaseGameId = 'game_0123456789abcdef0123456789abcdef';
const releaseUpstreamPath = `/api/game-distribution/releases/${releaseGameId}/index.html`;
const releaseBeforeCount = api.state.requests.length;
const releaseResponse = await expectHttp(
baseUrl,
`/games/${releaseGameId}/index.html`,
200,
'"upstream":"api"',
'平台同源发行入口转发到发行网关',
{
headers: {
'X-Request-Id': 'smoke-release-request-id',
Host: 'example.test',
Cookie: 'session=smoke-must-not-reach-release-gateway',
},
},
);
const releasePayload = JSON.parse(releaseResponse.body);
ensure(
releasePayload.url === releaseUpstreamPath,
`发行入口上游路径没有重写:${releasePayload.url}`,
);
const releaseUpstreamRequests = api.state.requests.slice(releaseBeforeCount);
ensure(
releaseUpstreamRequests.length === 1 &&
releaseUpstreamRequests[0].url === releaseUpstreamPath,
`发行入口上游请求不符:${describeRequests(releaseUpstreamRequests)}`,
);
ensure(
releaseUpstreamRequests[0]?.headers.cookie === undefined,
`发行入口没有清空 Cookie:${describeRequests(releaseUpstreamRequests)}`,
);
await expectHttp(
baseUrl,
'/games/detail',
200,
'site-shell',
'发行入口形状不符时 SPA 深链照常回退',
);
await expectHttp(
baseUrl,
'/games/game/index.html',
404,
'',
'发行入口形状不符时仍是真实 404',
);
await expectHttp(
baseUrl,
'/api/upload',
+12
View File
@@ -14,6 +14,7 @@ const PINGORA_GATEWAY_SOURCE = 'server-rs/crates/pingora-gateway/src/main.rs';
const VALID_KINDS = new Set([
'proxy',
'static',
'release_gateway',
'redirect_permanent',
'shadow_probe',
'not_found',
@@ -39,6 +40,8 @@ const REQUIRED_ROUTE_IDS = [
'generated_assets_forbidden',
'web_spa_fallback',
'profile_spa_fallback',
'games_spa_fallback',
'games_release_gateway',
'web_spa_case_trailing_slash',
'web_unknown_path_exact',
'creation_unknown_path_exact',
@@ -108,6 +111,15 @@ function validateExpectation(route) {
fail(`${context} 非 proxy 路由不能配置 protectionClass。`);
}
if (expect.kind !== 'release_gateway' && hasOwn(expect, 'upstreamPath')) {
fail(`${context} 只有 release_gateway 路由才能配置 upstreamPath。`);
}
if (expect.kind === 'release_gateway') {
requireString(expect.upstreamPath, `${context} upstreamPath`);
return;
}
if (expect.kind === 'static') {
if (!VALID_STATIC_ROOTS.has(expect.root)) {
fail(`${context} static root 不支持: ${expect.root}`);