|
|
@ -143,6 +143,24 @@ function isEnvelope<T>(value: unknown): value is ApiEnvelope<T> { |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 从错误响应里提取业务 code 与 message。 |
|
|
|
|
|
* |
|
|
|
|
|
* 后端**错误**响应是 `{code, message, requestId, timestamp}`,**没有 `data` 字段**; |
|
|
|
|
|
* 而 `isEnvelope` 要求 `data` 存在(那是给「成功响应解包」用的), |
|
|
|
|
|
* 若拿它判断错误体,会恒为 false,导致后端真实 message 被 `pickHttpMessage` 覆盖成 |
|
|
|
|
|
* 「请求参数有误」之类的笼统文案。故错误分支单独用本函数取值。 |
|
|
|
|
|
*/ |
|
|
|
|
|
function extractError(parsed: unknown): { code: number | null; message: string | null } { |
|
|
|
|
|
if (typeof parsed === 'object' && parsed !== null) { |
|
|
|
|
|
const obj = parsed as Record<string, unknown>; |
|
|
|
|
|
const code = typeof obj.code === 'number' ? obj.code : null; |
|
|
|
|
|
const message = typeof obj.message === 'string' && obj.message ? obj.message : null; |
|
|
|
|
|
return { code, message }; |
|
|
|
|
|
} |
|
|
|
|
|
return { code: null, message: null }; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
interface InternalOptions extends RequestOptions { |
|
|
interface InternalOptions extends RequestOptions { |
|
|
/** 标记这是刷新请求本身,避免 401 时递归刷新 */ |
|
|
/** 标记这是刷新请求本身,避免 401 时递归刷新 */ |
|
|
_isRefresh?: boolean; |
|
|
_isRefresh?: boolean; |
|
|
@ -247,7 +265,7 @@ async function rawRequest<T>(path: string, opts: InternalOptions): Promise<T> { |
|
|
} |
|
|
} |
|
|
throw new ApiError({ |
|
|
throw new ApiError({ |
|
|
httpStatus: 401, |
|
|
httpStatus: 401, |
|
|
code: isEnvelope<unknown>(parsed) ? parsed.code : 401, |
|
|
code: extractError(parsed).code ?? 401, |
|
|
message: '登录已失效,请重新登录', |
|
|
message: '登录已失效,请重新登录', |
|
|
requestId: resRequestId, |
|
|
requestId: resRequestId, |
|
|
}); |
|
|
}); |
|
|
@ -255,13 +273,11 @@ async function rawRequest<T>(path: string, opts: InternalOptions): Promise<T> { |
|
|
|
|
|
|
|
|
// HTTP 状态码优先(§8)
|
|
|
// HTTP 状态码优先(§8)
|
|
|
if (!response.ok) { |
|
|
if (!response.ok) { |
|
|
const msg = isEnvelope<unknown>(parsed) |
|
|
const err = extractError(parsed); |
|
|
? parsed.message |
|
|
|
|
|
: pickHttpMessage(response.status); |
|
|
|
|
|
throw new ApiError({ |
|
|
throw new ApiError({ |
|
|
httpStatus: response.status, |
|
|
httpStatus: response.status, |
|
|
code: isEnvelope<unknown>(parsed) ? parsed.code : response.status, |
|
|
code: err.code ?? response.status, |
|
|
message: msg, |
|
|
message: err.message ?? pickHttpMessage(response.status), |
|
|
requestId: resRequestId, |
|
|
requestId: resRequestId, |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|