修复登录注册验证码bug
This commit is contained in:
108
src/api/base.ts
108
src/api/base.ts
@@ -8,14 +8,31 @@ import { clearSession, getUserToken } from "./token"
|
||||
|
||||
type CallMode = "public" | "device" | "user"
|
||||
|
||||
const DEFAULT_TIMEOUT = 15_000
|
||||
|
||||
function captureHeaders(response: Response): Record<string, string> {
|
||||
const headers: Record<string, string> = {}
|
||||
response.headers.forEach((value, key) => {
|
||||
headers[key.toLowerCase()] = value
|
||||
})
|
||||
return headers
|
||||
}
|
||||
|
||||
async function request<R = undefined>(
|
||||
endpoint: string,
|
||||
init: {
|
||||
method: "GET" | "POST"
|
||||
body?: string
|
||||
auth?: string
|
||||
timeout?: number
|
||||
},
|
||||
): Promise<ApiResponse<R>> {
|
||||
const controller = new AbortController()
|
||||
const timer = setTimeout(
|
||||
() => controller.abort(),
|
||||
init.timeout ?? DEFAULT_TIMEOUT,
|
||||
)
|
||||
|
||||
try {
|
||||
const headers: HeadersInit = {}
|
||||
if (init.body !== undefined) {
|
||||
@@ -27,8 +44,10 @@ async function request<R = undefined>(
|
||||
method: init.method,
|
||||
headers,
|
||||
body: init.body,
|
||||
signal: controller.signal,
|
||||
})
|
||||
|
||||
const responseHeaders = captureHeaders(response)
|
||||
const contentType = response.headers.get("Content-Type") ?? "text/plain"
|
||||
|
||||
if (contentType.includes("text/plain")) {
|
||||
@@ -40,7 +59,7 @@ async function request<R = undefined>(
|
||||
message: text || "请求失败",
|
||||
}
|
||||
}
|
||||
return { success: true, data: undefined as R }
|
||||
return { success: true, data: undefined as R, headers: responseHeaders }
|
||||
}
|
||||
|
||||
if (contentType.includes("application/json")) {
|
||||
@@ -65,25 +84,36 @@ async function request<R = undefined>(
|
||||
return {
|
||||
success: true,
|
||||
data: (json.Data ?? json.data ?? undefined) as R,
|
||||
headers: responseHeaders,
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
status: response.status,
|
||||
message: json.Message || "请求失败",
|
||||
}
|
||||
}
|
||||
|
||||
return { success: true, data: json }
|
||||
return { success: true, data: json, headers: responseHeaders }
|
||||
}
|
||||
|
||||
throw new Error(`无法解析响应数据: ${contentType}`)
|
||||
} catch (e) {
|
||||
if (controller.signal.aborted) {
|
||||
return {
|
||||
success: false,
|
||||
status: 408,
|
||||
message: "请求超时,请稍后重试",
|
||||
}
|
||||
}
|
||||
console.error("后端请求异常:", e)
|
||||
return {
|
||||
success: false,
|
||||
status: 500,
|
||||
message: (e as Error).message || "网络错误",
|
||||
}
|
||||
} finally {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,40 +171,56 @@ async function call<R = undefined>(
|
||||
const body = data === undefined ? undefined : JSON.stringify(data)
|
||||
|
||||
const run = async (): Promise<ApiResponse<R>> => {
|
||||
let auth: string | undefined
|
||||
if (mode === "user") {
|
||||
const token = getUserToken()
|
||||
if (!token) {
|
||||
return {
|
||||
success: false,
|
||||
status: 401,
|
||||
message: "未登录或会话已过期",
|
||||
}
|
||||
}
|
||||
auth = `Bearer ${token}`
|
||||
} else if (mode === "device") {
|
||||
const token = await acquireDeviceToken()
|
||||
if (!token) {
|
||||
return {
|
||||
success: false,
|
||||
status: 401,
|
||||
message: "设备凭证获取失败",
|
||||
}
|
||||
}
|
||||
auth = `Bearer ${token}`
|
||||
}
|
||||
const maxAttempts = mode === "device" ? 2 : 1
|
||||
|
||||
const resp = await request<R>(endpoint, { method, body, auth })
|
||||
|
||||
if (!resp.success && resp.status === 401) {
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
||||
let auth: string | undefined
|
||||
if (mode === "user") {
|
||||
clearSession()
|
||||
const token = getUserToken()
|
||||
if (!token) {
|
||||
return {
|
||||
success: false,
|
||||
status: 401,
|
||||
message: "未登录或会话已过期",
|
||||
}
|
||||
}
|
||||
auth = `Bearer ${token}`
|
||||
} else if (mode === "device") {
|
||||
deviceToken = null
|
||||
deviceTokenExpire = 0
|
||||
if (attempt > 1) {
|
||||
// 上次请求 401,强制作废旧 token 再重新获取
|
||||
deviceToken = null
|
||||
deviceTokenExpire = 0
|
||||
}
|
||||
const token = await acquireDeviceToken()
|
||||
if (!token) {
|
||||
return {
|
||||
success: false,
|
||||
status: 401,
|
||||
message: "设备凭证获取失败",
|
||||
}
|
||||
}
|
||||
auth = `Bearer ${token}`
|
||||
}
|
||||
|
||||
const resp = await request<R>(endpoint, { method, body, auth })
|
||||
|
||||
if (!resp.success && resp.status === 401) {
|
||||
if (mode === "user") {
|
||||
clearSession()
|
||||
return resp
|
||||
}
|
||||
if (mode === "device" && attempt < maxAttempts) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
status: 401,
|
||||
message: "请求未授权",
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
if (method === "GET" && data === undefined) {
|
||||
|
||||
Reference in New Issue
Block a user