Files
ft/CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B-T正式KV普通业务请求恢复完整方案-待独立审查.md
Liubing\LB 6813da149a feat(upserver): 保存M2客户端KV迁移至本人统计写检查点
保存独立KV用户服务、固定会话存档与原业务接线,以及C3d资料缓存和C3e本人统计写。
保留原PF/AGG路线、业务公式和时序;榜单读取、好友资料、公告、匹配及首场景闸仍待完成。

验证:ServiceHost两条件各33组646断言;Unity CLI Loop编译0错误269警告。
包含相关方案、评审裁决、测试及状态文档。未操作服务器、正式账号或打包。
2026-09-30 19:19:05 +08:00

44 lines
8.0 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.
# M2 CP2B-T 正式 KV 普通业务请求恢复完整方案(待独立审查)
日期:2026-09-29。**本文只批准评审输入,不是编码批准。** 用户明确:`kvOnly` 对普通请求的拒绝是移植期临时处理,正式 KV 应像原业务流程一样走正常请求。按“同合同一次批级前审、批内连续实施、一次批末复核”减少审核往返;受审 hash 见同目录基线清单,报告落盘后主会话复算、逐项裁决、冻结白名单,再动生产代码。现有工作树保留,本机服务器源码不访问或修改。
## 1. 已核事实与批次边界
旧 `f40a816cc` 的 `CustomServerMgr.CustomServerPost/GetStringAsync` 以一个 `HttpClient` 发送普通业务请求。迁移提交 `0eb43b2b4` 加入 `kvOnly`,把普通 `SendAsync` 拒绝在入口;当前 `BindKVForGame` 复用此模式,`PlayerKVAccountLease.SendAsync` 只接受 `__kv_validation/ok` 和 `__kv_validation/unauthorized`。这证明拒绝是迁移门,不是线上 API 的产品合同。
正式 KV 登录已经通过同一 `S101AccountSession` 的 `CookieContainer` 创建互不共享的认证、KV、租约 handler;租约归 `PlayerKVLoginContext`,有 epoch/current、活动请求排水及 Close 屏障。租约在 31 模块 Apply **之前**就绑定到 `CustomServerMgr`;因此不能在 `BindKVForGame` 时立刻开放普通请求。CP3A 的原 handle 与 Setting/Club/Notification 交接完成之后,才有可作为本批“运输就绪”的时点。
本批目标:在正式 KV 已 GameLoaded、原 handle 和三原实例交接均成功时,现有 `ICustomServerMgr` 的 `GetStringAsync`、`CustomServerPost` 及 `Account/Event/Club/Friend/...Request` 包装方法可以通过**同一个账号租约和 Cookie**发送规范相对路径,并沿用现有“HTTP 200 返回正文,否则空结果/错误事件”的公共合同;旧会话、退出和 401/403 必须同步失效。非 KV/PF 分支行为不变。验证租约仍只准两个验证路由。**本批不开放 `FishingStage`,不调用正式 101/102,不声称任何业务 route 已在线上验证,也不迁 Survey/排行榜/首场景身份。** 运输可用与某个业务接口在当前线上存在是两个验收结论。
## 2. 路线比较与选择
| 路线 | 收益 | 问题 | 裁决建议 |
|---|---|---|---|
| A. 去掉 `kvOnly`,给旧 `client` 填登录 Cookie | 改动少 | 租约与第二 `HttpClient` 分离,退出排水/epoch/handler 所有权无法沿用;Apply 中可过早发送 | 不采用 |
| B. 扩展既有账号租约的**正式模式**,由普通包装方法转发 | 同一次认证与 Cookie、已有关闭屏障及会话版本;无第二登录 | 需区分正式/验证路由、运输就绪与公开授权,并补退场/401 竞态测试 | **推荐** |
| C. 为业务另建第四 transport/租约 | 职责可分 | 新 handler 所有权、Cookie/Close/版本并发面和基线回归增加;当前无必要 | 暂不采用 |
## 3. 合同与时序
1. `PlayerKVControlledLoadCapability` 已有 formal/validation 不可变模式。在现有 `PlayerKVAccountLease` 内据此区分路由:**验证模式保持原精确两路由不变**;正式模式接受 GET/POST 的规范相对业务路径,拒绝空、绝对/跨源 URL、以 `/` 或 `\\` 开头、`//`、`?`、`#`、`%` 编码、控制字符、`.`/`..` 段及反斜线。正式模式也拒绝 `__kv_validation/*`、`account/Login` 和 `playerdata/*`,避免重认证、绕过专用 KV 传输。路由大小写保持客户端原值,不自动改名。不能以“只列 Mail/Friend”再造一个临时全局禁用门;所有合规普通路由走相同运输合同,**业务语义另按批审**。
2. `CustomServerMgr.BindKVForGame` 仍在 Apply 前绑定并废弃旧空闲 PF transport,但将正式普通请求标记为**未就绪**。只在 `LoginKVFormalAsync` 核同 epoch 的 GameLoaded、CP3A 三原实例绑定成功、原 handle 仍当前后,由 `UserService.KVLoad` 一次调用内部 `EnableKVBusiness(epoch)`;管理器只核自身 formal 租约、固定 API、相同 epoch、尚未关闭及单次发布,不反向依赖 UserService/Coordinator。验证实例从未启用。`PFLoginAct` 仍停在登录页,现阶段不会自动发业务请求。
3. `CustomServerMgr.SendAsync` 在 KV 就绪时捕获原 lease 与 `SessionVersion`,通过其 `SendAsync` 发请求;HTTP 200 且响应仍属同租约/版本/epoch 才返回正文。旧响应、取消、退出与会话替换返回空,不更新业务状态。401/403 用当前版本专用 KV 未授权事件使 `PlayFabUserService` **先同步撤销就绪与公开身份/原 handle,再交 Coordinator 关闭**;不走 PF 自动重登。其他状态/超时保留现有空结果和受控错误日志,不把响应体、Cookie 或存档写入日志。`CustomServerMgr.UseAccountSession` 在 KV 模式继续拒绝第二次认证。
4. `LogoutFormalKV`、Quit、加载/绑定失败与 `ClearKVForGame` 在任何 await 前同步禁用普通请求、递增 `SessionVersion` 并触发 `SessionChanged`,随后租约排水关闭;旧回包不能发布未授权或覆盖新身份。`PlayerKVAccountLease.CloseAsync` 仍负责活动请求取消/排水;失败保留关闭屏障。PF 分支的 transport 与事件语义不变。
5. `ICustomServerMgr.Cookie` 是现有 `RTService.Connect()` 的会话输入。正式 KV 运输就绪且租约仍当前时可返回**同一账号 CookieContainer**;未就绪/已撤销仍拒绝。`SessionChanged` 与 `RTService` 已有 `SessionVersion` 检查必须使旧 SignalR 连接失效。本批不声称 SignalR 真实连接完成,G5 另验;但不能留下“普通 HTTP 已开而现有 `Cookie` 永远抛异常”的隐藏冻结。
## 4. 精确实施边界
| 生产文件 | 允许的修改 |
|---|---|
| `Client/Assets/Scripts/Services/PlayerData/PlayerKVLoginContext.cs` | 在既有 capability/租约中区分正式与验证模式、规范路由检查、仅向当前就绪租约交接原 CookieContainer 引用;不改变登录、KV cache/owner、验证两路由、Close 先后 |
| `Client/Assets/Scripts/Core/CustomServerMgr.cs` | KV 普通请求在明确就绪后转发同一租约;同步禁用、版本和 Cookie/401 处理;PF 旧分支不改 |
| `Client/Assets/Scripts/Services/UserService.KVLoad.cs` | CP3A 成功交接后一次启用、KV 未授权与 Logout/失败先失效再关闭;不公开旧 `UserId` 或跳场景 |
测试仅可增改 `CodexOutput/upserver/KVGameLoadTests` 与固定 Unity CLI Loop Editor 验证入口中实际必要的合成用例;不得顺手改 `LoginStage`、`FishingStage`、`PFLoginAct`、`UserService.cs`、KVMgr/Guard/Owner/Coordinator、Schema、场景/Prefab、服务端或配置。若实施证明白名单不够,先补审精确增量,不以测试绿灯倒推代码许可。
## 5. 验收与批末复核
合成 handler 必须证明:一次账号认证、三 handler 同 Cookie 且不同实例;正式就绪前普通 GET/POST 零发送,就绪后 `mail/fetch`、`friend/GetInvitedListCount`、`club/GetSelfClub` 等**仅作为路径/正文示例**由原租约发送且保持 JSON/Content-Type;验证租约仍只认两个验证路由。异常/绝对/编码路径、专用认证及 KV 路由零发送。200/非200、401/403、取消、退出中的旧响应、同账号新 epoch、账号切换、Close 失败逐项验证无 PF 回退、无旧结果/身份污染;`Cookie` 与 `SessionVersion` 只在当前就绪租约有效。再跑既有 CP2A/CP3A/B01/B02 回归和 Unity CLI Loop Editor 编译,记录正式请求 0;真实 Player 编译仍按工具限制标未验。批末封存 hash、一次独立复核和主会话裁决,每检查点更新日志。
`FishingStage` 仍保持 [LoginStage 阶段闸](../../../../Client/Assets/Scripts/Stages/LoginStage.cs),直到 Mail/Survey/排行榜/Friend/AntiCheat/活动、公开身份/授权和真正线上响应合同另批完成,并按[最终门控清单](M2-最终通关前临时门控与忽略路径清理清单-2026-09-29.md)销账。固定正式地址 `http://s101.local:18080/`;仅 Unity CLI Loop,不用 UnitySkills,暂不打包。