修复全量审查问题;接入vitest;精简IdP图标逻辑
CI / test (push) Successful in 46s

This commit is contained in:
2026-07-22 16:51:45 +08:00
parent efcb84eaa8
commit 119f60516c
39 changed files with 1164 additions and 797 deletions
+19 -4
View File
@@ -32,7 +32,7 @@ function buildUrl(path: string, query?: RequestOptions['query']): string {
return s ? `${BASE}${path}?${s}` : BASE + path
}
async function parseError(resp: Response): Promise<never> {
async function parseError(resp: Response, sentToken: string): Promise<never> {
let message = `请求失败(${resp.status})`
let ociCode: string | undefined
try {
@@ -54,7 +54,7 @@ async function parseError(resp: Response): Promise<never> {
} catch {
/* 非 JSON 响应体,保留默认消息 */
}
if (resp.status === 401) useAuthStore().logout()
if (resp.status === 401) handleUnauthorized(sentToken)
// 全局限速(429)整页拦截;登录接口的 429 是账号锁定,留在表单内提示
if (resp.status === 429 && !resp.url.includes('/auth/login') && location.pathname !== '/blocked') {
location.assign('/blocked')
@@ -62,17 +62,31 @@ async function parseError(resp: Response): Promise<never> {
throw new ApiError(resp.status, message, ociCode)
}
/** 401 处理:仅当失败请求发送时的 token 仍是当前会话 token 才登出——换发新
* token 后(OAuth 绑定回跳等),旧 token 请求的迟到 401 不得清掉新会话;
* 登出后带 redirect 统一跳登录页,不把用户留在满屏报错的页面上。 */
function handleUnauthorized(sentToken: string) {
const auth = useAuthStore()
if (sentToken !== auth.token) return
auth.logout()
if (location.pathname !== '/login') {
const redirect = encodeURIComponent(location.pathname + location.search)
location.assign(`/login?redirect=${redirect}`)
}
}
/** 统一请求封装:注入 JWT、401 登出、错误转 ApiError */
export async function request<T>(path: string, opts: RequestOptions = {}): Promise<T> {
const auth = useAuthStore()
const headers: Record<string, string> = { 'Content-Type': 'application/json', ...opts.headers }
if (auth.token) headers.Authorization = `Bearer ${auth.token}`
const sentToken = auth.token
const resp = await fetch(buildUrl(path, opts.query), {
method: opts.method ?? 'GET',
headers,
body: opts.body === undefined ? undefined : JSON.stringify(opts.body),
})
if (!resp.ok) await parseError(resp)
if (!resp.ok) await parseError(resp, sentToken)
// 202/204 等成功响应可能无 body,直接 resp.json() 会抛 Unexpected end of JSON input
const text = await resp.text()
return (text ? JSON.parse(text) : undefined) as T
@@ -91,12 +105,13 @@ export async function rawFetch(
const auth = useAuthStore()
const headers: Record<string, string> = { ...opts.headers }
if (auth.token) headers.Authorization = `Bearer ${auth.token}`
const sentToken = auth.token
const resp = await fetch(buildUrl(path, opts.query), {
method: opts.method ?? 'GET',
headers,
body: opts.body,
})
if (!resp.ok) await parseError(resp)
if (!resp.ok) await parseError(resp, sentToken)
return resp
}