Files
quyun-v2/frontend/shared/apiError.ts
2025-12-17 11:48:53 +08:00

52 lines
2.2 KiB
TypeScript

export type FriendlyApiError = {
summary: string
detail?: string
}
type MaybeAxiosError = {
isAxiosError?: boolean
response?: { status?: number; data?: unknown }
code?: string
message?: string
}
function stringifyMaybe(value: unknown): string {
if (value == null) return ''
if (typeof value === 'string') return value
try {
return JSON.stringify(value)
} catch {
return String(value)
}
}
export function toFriendlyApiError(err: unknown): FriendlyApiError {
const maybeAxios = err as MaybeAxiosError | null
const isAxiosError = Boolean(maybeAxios && typeof maybeAxios === 'object' && maybeAxios.isAxiosError)
if (!isAxiosError) {
const detail = err instanceof Error ? err.message : stringifyMaybe(err)
return { summary: '请求失败', detail: detail || undefined }
}
const status = maybeAxios?.response?.status
const data: any = maybeAxios?.response?.data
const serverMessage = stringifyMaybe(data?.message || data?.error || data)
if (!status) {
if (maybeAxios?.code === 'ECONNABORTED') return { summary: '请求超时', detail: '服务器响应超时,请稍后重试。' }
if (maybeAxios?.code === 'ERR_NETWORK' || maybeAxios?.message === 'Network Error') {
return { summary: '无法连接到服务器', detail: '请确认后端服务已启动,或检查网络/CORS 配置。' }
}
if (maybeAxios?.code === 'ERR_CANCELED') return { summary: '请求已取消' }
return { summary: '网络异常', detail: '请检查网络连接或稍后重试。' }
}
if (status === 401) return { summary: '登录已失效', detail: serverMessage || '请重新登录后继续操作。' }
if (status === 403) return { summary: '没有权限', detail: serverMessage || '当前账号无权限访问该资源。' }
if (status === 404) return { summary: '资源不存在', detail: serverMessage || '接口不存在或已下线。' }
if (status >= 500) return { summary: '服务器异常', detail: serverMessage || '服务端发生错误,请稍后重试。' }
if (status === 400) return { summary: '请求参数错误', detail: serverMessage || '请检查输入内容后重试。' }
return { summary: `请求失败 (${status})`, detail: serverMessage || undefined }
}