游戏在线游玩加载体验:进入游玩长时间黑屏/空白且无加载反馈(网页用户端 + 后台试玩) #636
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
现象
用户反馈(IM 截图):「进入游玩得有个游戏加载页面,现在加载有点慢,一直黑屏体验不好」。
范围(用户确认):网页用户端
/games/play与后台管理端「游戏审核 → 待审版本试玩」两处。复现与实测
环境:本地真实栈(真实 SpacetimeDB + 真实私有 OSS + 真实发行包)+ 真实 Chromium,链路按 4 Mbps 下行 / 100 ms RTT 模拟(按真实线字节数延迟后再原样投递响应)。
夹具:按真实 AGC 发行包形状打包 —— 根
index.html+ 真实 Phaser 4 压缩包assets/phaser.min.js(1,375,976 B)+assets/game.js+assets/logo.png,审核通过后从网页进入游玩。/games/play游戏正在启动…opacity:1出现,区域全白空白,页面全程未出现任何加载文案phaser.min.js1,375,976 B 原样下发(模拟耗时 2724 ms)发行网关响应头实测(
GET /games/<gameId>/…):Content-EncodingCache-Controlindex.htmlpublic, max-age=60, must-revalidateassets/phaser.min.jsassets/game.js即使显式带
Accept-Encoding: gzip, deflate, br,仍是 1,375,976 B 原样返回。根因
src/components/game-distribution/GamePlayPage.tsx的.game-player-loading覆盖在#17131b近黑壳(.game-player-shell)上,文案仅「游戏正在启动…」,没有封面、进度、动效;.game-player-frame在onLoad前opacity: 0。用户看到的就是「黑屏 + 一行小字」。onLoad:文档加载完成 ≠ 游戏可玩。实测包内Phaser脚本 3041 ms 才执行、场景 3253 ms 才出画面,onLoad只是这两者之间的近似;换更重的包时误差会更大。apps/admin-web/src/pages/AdminGameDistributionReviewPage.tsx拿到previewUrl后直接渲染<iframe class="admin-game-review-preview">(CSS 只有min-height: 42rem)。没有加载提示、没有超时、没有失败/会话过期提示 —— 预览会话过期或资源 404 时,审核员会永远停在空白区域。serve_release_asset/serve_admin_version_preview_asset_inner把 ZIP 里解压出来的字节直出,不下发Content-Encoding。Phaser 4 的 1.34 MB 压缩包对用户是 1.34 MB 实传;4 Mbps 下光这一个文件约 2.7 s,这也是「加载慢」的主因。修改方案
前端(两处共用同一个共享组件,避免两端再次跑偏)
packages/shared共享组件:游戏加载面 —— 封面/标题 + 动效进度指示 + 按时长派生的阶段文案(准备中 → 正在加载游戏资源 → 正在启动游戏)+ 「等待较久」的安抚提示;role="status"、aria-live语义,移动端优先。GamePlayPage:把一行字的.game-player-loading换成该加载面;ready之后才淡入 iframe(保留现有 220 ms 过渡),超时后仍是现有「重试 / 返回」面板。AdminGameDistributionReviewPage:试玩区域包同一加载面,iframe 加载完成才显示;补预览会话失败/资源 404 的错误提示与重试入口,不留空白。后端(只作用于发行网关路由)
text/html、text/javascript、text/css、application/json、image/svg+xml等)按Accept-Encoding下发 gzip/deflate,图片/音频/视频等已是压缩格式的不动;CSP、X-Content-Type-Options、CORP/CORS、Cache-Control语义保持不变。验收判据
assets/phaser.min.js改为Content-Encoding: gzip(约 1,376 KB → 约 330 KB),该文件在 4 Mbps 下的等待由 ~2.7 s 降到 ~0.7 s;Cache-Control/ CSP / CORP / CORS 与现状一致。check:game-distribution-web-e2e、check:game-distribution-sandbox-e2e、check:game-distribution-ops-rollback-e2e、admin-web 与 web 的定向测试保持通过。证据与说明
publicationRevision、审核 CAS、沙箱口径与发行入口路由;/games/<gameId>/路径与 Cookie 拒绝语义不变。已在
fix/game-play-loading上完成,PR:#639(含前端/后端改动、测试与截图对照)。根因(真实栈复现,非推断)
真实发行包夹具(根
index.html+ 真实 Phaser 4 压缩包phaser.min.js1,375,976 B)+ 真实 Chromium,链路按 4 Mbps / 100 ms 模拟:#17131b近黑壳 + 一行游戏正在启动…(实测 99.3% 像素亮度 < 24),ready判定只看 iframeonLoad(文档加载完成 ≠ 游戏可玩)→ 用户看到的就是「黑屏 + 一行小字」。AdminGameDistributionReviewPage拿到previewUrl后直接渲染<iframe class="admin-game-review-preview">(CSS 只有min-height: 42rem)——没有加载态、没有超时、没有失败提示,加载期是一片空白,会话过期或资源 404 也会永远停在空白。phaser.min.js1,375,976 B 原样下发(Content-Encoding: none)、无 ETag,60 秒max-age过后浏览器只能重下整包。改动(PR #639)
PlatformGameLoadingSurface(packages/shared):封面/标题 + 动效进度 + 阶段文案(准备 → 加载资源 → 启动引擎)+ 慢加载提示;网页游玩页与后台试玩共用,两端加载上限统一为PLATFORM_GAME_LOADING_TIMEOUT_MS(20 秒),后台超时给「重新创建试玩会话」。Content-Encoding: gzip+Vary;下发强ETag,命中If-None-Match返回 304。max-age=60, must-revalidate与撤销窗口不变。cargo test -p api-server -- game_distribution49 passed(含 5 条新增)、check:game-distribution-ops-rollback-e2e47 PASS(含 4 条新增)、共享/游玩页/后台试玩三条前端用例、typecheck 与编码检查全通过。实测对照(同一 4 Mbps 模拟链路)
phaser.min.js传输用户端加载面实测截图、后台加载面实测截图与两条「画面就绪」对照见 PR #639 正文。
实拍截图
用户端加载面:
后台试玩加载面: