Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pac
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tools
pac
Commits
7196ad06
Commit
7196ad06
authored
Aug 20, 2026
by
luoqi
Browse files
Options
Browse Files
Download
Plain Diff
merge: fix/refresh-single-flight → test(冷启动换票走共享单飞)
parents
504b0e19
2207d61b
Pipeline
#3585
failed in 0 seconds
Changes
1
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
21 additions
and
8 deletions
+21
-8
apps/pac-web/src/hooks/use-auth-bootstrap.ts
+21
-8
No files found.
apps/pac-web/src/hooks/use-auth-bootstrap.ts
View file @
7196ad06
...
...
@@ -2,7 +2,7 @@
import
{
useEffect
,
useRef
,
useState
}
from
'react'
;
import
{
useAuthStore
}
from
'@/stores/auth-store'
;
import
{
exchangeCode
,
refreshToken
}
from
'@/lib/auth-api'
;
import
{
exchangeCode
}
from
'@/lib/auth-api'
;
import
{
tryRefresh
}
from
'@/lib/api-client'
;
import
{
env
}
from
'@/lib/env'
;
...
...
@@ -195,20 +195,33 @@ export function useAuthBootstrap() {
}
// ─── 3. 仅 refresh token 还在 → silent refresh ───
//
// 🔴 **必须走 api-client 的共享单飞 `tryRefresh`**,⛔ 不能直接调 `refreshToken()`。
// refresh token 是**一次性**的:服务端换票时 `redis.del(旧 jti)` 再发新的
// (auth.service.ts:468)。所以同一张票被两条路各换一次,后到的那条必得
// `10103 AUTH_INVALID_REFRESH_TOKEN` → 前端据此清会话 → 「登录已过期」。
//
// ── 2026-08-20 生产实录(client-diag)────────────────────────
// ev=start accessValid=N ← access 到点过期
// ev=refresh-ok ← 本函数直接换,成功,旧 jti 已作废
// ev=runtime-refresh-fail err=code=10103 ← 首屏请求 401 兜底刷,拿的是同一张旧票
// ev=runtime-auth-clear err=code=10106 ← 清凭据,弹「登录已过期」
// 主管当时什么都没做错,只是隔了 2 小时回到页面。
//
// ⚠️ 下面那个"过期前 60s 定时刷"**早就改成走单飞了**(见本文件末尾那段注释,
// 同一条根因),⛔ 唯独这里漏了 —— 而这里恰恰是**每次冷启动**都会走的路径,
// 比定时器常见得多。
if
(
s
.
refreshToken
)
{
setStatus
(
'authenticating'
);
try
{
const
r
=
await
refreshToken
(
s
.
refreshToken
);
setTokens
(
r
);
const
ok
=
await
tryRefresh
();
// 成功即 setTokens、失败即 clear,内部已处理
if
(
ok
)
{
reportDiag
({
ev
:
'refresh-ok'
,
codeTag
});
setStatus
(
'ready'
);
return
;
}
catch
{
}
else
{
reportDiag
({
ev
:
'refresh-fail'
,
codeTag
,
...
storeSnap
(),
...
envInfo
});
clear
();
setStatus
(
'error'
);
return
;
}
return
;
}
// ─── 4. 全没了 → 弹「登录已过期」───
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment