合并 origin/master(51cb05f41,22 个提交)到 feat/game-purchase
- 逐块合并 server-rs/crates/api-server/src/modules/game_distribution.rs:以 master 的 ReleaseAssetResponseInput / 5 参 release_asset_response_with_cache / ETag / 304 / gzip 结构为准,并在其上保留本分支的付费 404 守卫(price_mud_points > 0 仍在 release_package_bytes 读包之前返回);播放会话资源响应改用同一结构(etag None、cache_control no-store、沿用 accept-encoding 协商)。 - 合并 src/components/game-distribution/GamePlayPage.tsx:接入 master 的共享 PlatformGameLoadingSurface 与 PLATFORM_GAME_LOADING_TIMEOUT_MS,删除本地重复常量 GAME_PLAY_STARTUP_TIMEOUT_MS 与裸 div,买断制播放会话准备态改由共享加载面承载。 - 合并 src/components/game-distribution/GameDetailPage.tsx:同时保留 master 的 onOpenCreator 作者插槽与本分支的买断制购买弹窗、onOpenRecharge 充值入口。 - 合并 vite.config.ts:保留 master 的 /api/creators 代理,并保留 play-sessions 前缀清 Cookie 规则(顺序仍在通用 /api/game-distribution 之前)。 - 合并 deploy/nginx/README.md:保留 master 的 SPA allowlist 门禁口径(含 /creators、/creators/connections)与本分支的播放会话前缀章节;三份 nginx 模板的 ^~ play-sessions location 与清 Cookie 原样保留。 - 合并 apps/admin-web/src/pages/AdminGameDistributionReviewPage.test.tsx:保留 master 的加载面/超时用例与本分支的审核价格(冻结价优先、历史按 0)用例。 - 合并 src/components/game-distribution/GameDistributionPages.test.tsx:保留双方 mock,并新增「付费作品在会话签发期间显示共享加载面」用例。 - 合并 docs/【玩法创作】平台入口与玩法链路-2026-05-15.md(保留买断制合同并回填 master 的创作者主页与关注粉丝合同)、decision-log.md、pitfalls.md:追加双方条目,不改写任一侧正文。 - 保留 master 侧新增能力:release_asset_etag / if_none_match_matches / accepts_gzip_encoding / gzip_release_asset / release_asset_not_modified_response、SPA 加载面、创作者主页与关注粉丝(user_follow 表、creator 查询与 author_id 过滤)。
This commit is contained in:
@@ -183,7 +183,7 @@ http {
|
||||
try_files /index.html =404;
|
||||
}
|
||||
|
||||
location ~* "^/(?:creation|editor/canvas|pay|profile|profile/payment|project|components|design-system|games|games/detail|games/mine|games/play|games/publish)/?$" {
|
||||
location ~* "^/(?:creation|editor/canvas|pay|profile|profile/payment|project|components|design-system|creators|creators/connections|games|games/detail|games/mine|games/play|games/publish)/?$" {
|
||||
try_files $uri /index.html =404;
|
||||
}
|
||||
|
||||
|
||||
@@ -104,10 +104,12 @@ curl -sSI -H 'Accept-Encoding: br' \
|
||||
|
||||
- 现役发行入口是平台同源路径 `https://<平台域名>/games/<gameId>/`。三份常驻模板(`genarrative.conf`、`genarrative-dev-http.conf`、容器 `deploy/container/nginx.conf`)都内联同一条同源发行入口 location,把 `/games/<gameId>/` 与 `/games/<gameId>/<asset>` 转发到 `api-server` 发行网关;不再需要独立发行域名、`*.games.<域名>` 通配 DNS 或通配 TLS。
|
||||
- 该 location 的正则必须整体加双引号:`location ~ "^/games/(?<game_id>game_[0-9a-f]{32})(?<game_path>/.*)?$"`。不加引号时 nginx 会把 `{32}` 当块定界符,`nginx -t` 报 `pcre2_compile() failed: missing closing parenthesis`。
|
||||
- 发行入口不使用 Cookie:边缘转发前设置 `proxy_set_header Cookie ""`;`api-server` 发行网关也会拒绝带 Cookie 的请求。响应头(`X-Content-Type-Options`、CORP、无凭据 CORS、HTML CSP、内容类型白名单与 `Cache-Control: public, max-age=60, must-revalidate`)由 `api-server` 发行网关设置,边缘不覆盖。
|
||||
- 发行入口不使用 Cookie:边缘转发前设置 `proxy_set_header Cookie ""`;`api-server` 发行网关也会拒绝带 Cookie 的请求。响应头(`X-Content-Type-Options`、CORP、无凭据 CORS、HTML CSP、内容类型白名单、`ETag` 与 `Cache-Control: public, max-age=60, must-revalidate`)由 `api-server` 发行网关设置,边缘不覆盖。
|
||||
- 传输编码:发行网关自己对文本类资源(HTML/JS/CSS/JSON/SVG/WASM,≥1 KiB)下发 `Content-Encoding: gzip` + `Vary: Accept-Encoding`,边缘的 gzip/Brotli 不会二次压缩(两边都以「上游已带 `Content-Encoding` 就跳过」收口),因此本地 dev(Vite 代理)与 nginx 边缘的用户口径一致,不再有「本地引擎包原样 1.31 MiB」的落差。注意 **Pingora 网关在自身压缩关闭时会移除请求里的 `Accept-Encoding`**,那种部署形态下源站压缩不生效、边缘也不压,属于网关侧口径(见 `docs/project-memory/shared-memory/pitfalls.md` 2026-10-05 条目)。
|
||||
- 条件请求:命中 `If-None-Match` 时发行网关直接返回 `304`(无正文,保留 `Cache-Control` 与 `ETag`),所以 60 秒 `max-age` 之后的重复游玩只重验证、不重下整包;下架与换版仍按 60 秒窗口在新请求上生效。
|
||||
- 隔离靠 iframe 沙箱而不是独立来源:游戏文档跑在 `sandbox="allow-scripts"` 的不透明来源里,读不到主站 Cookie、storage 与 DOM,离开页面即随 iframe 卸载。
|
||||
- 审核通过时 `api-server` 按 gameId 派生同源路径 `/games/<gameId>/` 作为 `entryUrl` 写入公开投影,部署侧不再需要配置发行域名。换版本或下架只改变后端公开投影,边缘不需要改配置。
|
||||
- 门禁:`npm run check:nginx-spa-routes` 校验三份模板的 SPA allowlist(含 `/games`、`/games/detail`、`/games/play`、`/games/mine`、`/games/publish`、`/pay`、`/profile/payment`)与收银台深链前缀路由 `location ~* "^/pay/[^/]+/?$"`(`/pay/<checkoutToken>` 只放行「前缀 + 恰好一个路径段」;只放行裸前缀会让真实收银台链接落到默认 location 变 404),脚本自带正/反用例。历史上的独立来源模板与专属门禁已随同源方案上线删除。
|
||||
- 门禁:`npm run check:nginx-spa-routes` 校验三份模板的 SPA allowlist(含 `/creators`、`/creators/connections`、`/games`、`/games/detail`、`/games/play`、`/games/mine`、`/games/publish`、`/pay`、`/profile/payment`)与收银台深链前缀路由 `location ~* "^/pay/[^/]+/?$"`(`/pay/<checkoutToken>` 只放行「前缀 + 恰好一个路径段」;只放行裸前缀会让真实收银台链接落到默认 location 变 404),脚本自带正/反用例。历史上的独立来源模板与专属门禁已随同源方案上线删除。
|
||||
|
||||
## 付费游戏播放会话前缀(`/api/game-distribution/play-sessions/`)
|
||||
|
||||
|
||||
@@ -238,7 +238,7 @@ server {
|
||||
try_files /index.html =404;
|
||||
}
|
||||
|
||||
location ~* "^/(?:creation|editor/canvas|pay|profile|profile/payment|project|components|design-system|games|games/detail|games/mine|games/play|games/publish)/?$" {
|
||||
location ~* "^/(?:creation|editor/canvas|pay|profile|profile/payment|project|components|design-system|creators|creators/connections|games|games/detail|games/mine|games/play|games/publish)/?$" {
|
||||
error_page 503 /maintenance.html;
|
||||
|
||||
if ($genarrative_maintenance) {
|
||||
|
||||
@@ -266,7 +266,7 @@ server {
|
||||
try_files /index.html =404;
|
||||
}
|
||||
|
||||
location ~* "^/(?:creation|editor/canvas|pay|profile|profile/payment|project|components|design-system|games|games/detail|games/mine|games/play|games/publish)/?$" {
|
||||
location ~* "^/(?:creation|editor/canvas|pay|profile|profile/payment|project|components|design-system|creators|creators/connections|games|games/detail|games/mine|games/play|games/publish)/?$" {
|
||||
error_page 503 /maintenance.html;
|
||||
|
||||
if ($genarrative_maintenance) {
|
||||
|
||||
Reference in New Issue
Block a user