修复 AGC 维护期登录错误提示
Project CI / AI game creator shell Rust shard 2/4 (push) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (push) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (push) Has been cancelled
Project CI / AI game creator shell Rust smoke (push) Has been cancelled
Project CI / AI game creator shell Rust crates (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Native shell 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 shard 1/4 (push) Has been cancelled

按 HTTP 状态展示认证服务不可用、超时和维护提示

增加 503 非 JSON 维护页认证界面回归测试

同步 AGC 启动认证错误提示技术方案
This commit is contained in:
kdletters
2026-09-15 23:29:22 +08:00
parent 34db1b6ad1
commit 34503990f2
3 changed files with 56 additions and 4 deletions
@@ -72,6 +72,24 @@ export function getClientAuthRefreshOperation(apiBaseUrl: string) {
const CLIENT_AUTH_NETWORK_ERROR_MESSAGE =
'无法连接登录服务,请确认配套后端或 API 代理已启动后重试';
function getClientAuthHttpErrorMessage(status: number, fallback: string) {
switch (status) {
case 408:
case 504:
return '登录服务响应超时,请检查服务器地址和网络后重试';
case 429:
return '登录请求过于频繁,请稍后重试';
case 500:
return '登录服务内部错误(HTTP 500),请稍后重试';
case 502:
return '登录服务暂不可用:上游服务请求失败,请稍后重试';
case 503:
return '登录服务暂不可用(HTTP 503),服务器可能正在维护,请稍后重试';
default:
return fallback;
}
}
function getClientAuthNetworkErrorMessage(error: unknown) {
const detail =
error instanceof Error ? error.message.trim() : String(error).trim();
@@ -121,24 +139,26 @@ export function getClientAuthErrorMessage(error: unknown, fallback: string) {
}
async function readAuthErrorMessage(response: Response, fallback: string) {
const httpFallback = getClientAuthHttpErrorMessage(response.status, fallback);
const text = await readClientHttpResponseText(response, {
url: 'auth error response',
});
if (!text.trim()) {
return fallback;
return httpFallback;
}
let parsed: unknown;
try {
parsed = JSON.parse(text) as unknown;
} catch {
return fallback;
return httpFallback;
}
try {
unwrapApiResponse(parsed);
} catch (error) {
return error instanceof Error ? error.message : fallback;
const message = error instanceof Error ? error.message.trim() : '';
return message && message !== '请求失败' ? message : httpFallback;
}
return fallback;
return httpFallback;
}
async function requestAuthJson<T>(
@@ -1272,6 +1272,37 @@ export function registerAuthTests() {
).toHaveLength(1);
});
it('shows the HTTP maintenance error when startup auth receives a 503', async () => {
window.localStorage.setItem(
'genarrative.auth.access-token.v1',
'existing-token',
);
vi.spyOn(globalThis, 'fetch').mockImplementation(
async (input: RequestInfo | URL) => {
if (String(input) === '/api/auth/me') {
return new Response(
'<!doctype html><title>503 Service Unavailable</title>',
{ status: 503, headers: { 'Content-Type': 'text/html' } },
);
}
throw new Error(`unexpected fetch ${String(input)}`);
},
);
render(
React.createElement(AuthenticatedClient, null, () =>
React.createElement('main', { 'aria-label': '已登录' }),
),
);
expect(await screen.findByRole('main', { name: '登录' })).not.toBeNull();
expect(
screen.getByText(
'登录服务暂不可用(HTTP 503),服务器可能正在维护,请稍后重试',
),
).not.toBeNull();
});
it('still calls logout when token refresh fails during logout retry', async () => {
window.localStorage.setItem(
'genarrative.auth.access-token.v1',
@@ -63,6 +63,7 @@ npm 游戏的可预览产物固定为对应 package 目录下的 `dist/index.htm
- AGC 客户端启动恢复按“读取本地凭据 → 刷新会话(无 token 或失效时)→ 读取当前用户 → Tauri 本地运行时会话安装”阶段执行。界面必须展示当前阶段和已等待时间;不能以无期限的单一 loading 文案隐藏网络或 Runner 故障。
- 客户端 HTTP 传输默认使用 15 秒超时并通过独立 `AbortController` 终止请求;调用方可为确需长耗时的请求显式传入 `timeoutMs: null`。调用方主动取消仍保留原始 `AbortError`,超时使用稳定的 `ClientHttpTimeoutError`,由认证层转换为可操作的中文提示。
- 会话恢复或本地 Runner 连接超时后必须进入登录页并提供“重试登录状态检查”。重试递增恢复代次并以运行标识忽略旧恢复任务的迟到 UI 写回;不得清除仍可用于后续重试的 access token,也不得重复并发刷新同一服务器的 refresh 请求。
- AGC 壳启动认证遇到空响应、非 JSON 维护页或 5xx 时,必须按 HTTP 状态生成可操作的中文提示(503 明确标记服务暂不可用/可能维护),不能退化为 `读取当前用户失败`;后端返回的结构化错误 message 仍优先展示。
- Tauri Runner 的启动与 IPC 超时继续以 `runner/protocol.rs` 的 30 秒启动、10 秒读写为权威;启动等待循环会把 endpoint 探测预算裁剪到剩余启动期限,避免单次 ping 把 30 秒门禁延长。考虑复用旧 endpoint 前可能先消耗一次 IPC 等待,前端 UI 兜底取 45 秒,不改变 Runner 协议、启动策略或认证接口。
## 2026-08-26 运行中自主扩图提案