Include error response body in API client errors

This commit is contained in:
CPTProgrammer
2026-07-06 23:29:54 +08:00
parent a823863d0b
commit 95af305966
3 changed files with 26 additions and 5 deletions
+8 -3
View File
@@ -1,3 +1,5 @@
import { readErrorBody } from "../utils/fetch";
/** CurseForge API 客户端,封装两套 API 的鉴权与 User-Agent。 */ /** CurseForge API 客户端,封装两套 API 的鉴权与 User-Agent。 */
export class CurseForgeClient { export class CurseForgeClient {
/** GET /v1/mods/{modId}/files 等只读接口 */ /** GET /v1/mods/{modId}/files 等只读接口 */
@@ -38,8 +40,9 @@ export class CurseForgeClient {
headers: this.apiHeaders(), headers: this.apiHeaders(),
}); });
if (!res.ok) { if (!res.ok) {
const body = await readErrorBody(res);
throw new Error( throw new Error(
`CurseForge API GET ${path} failed: ${res.status} ${res.statusText}`, `CurseForge API GET ${path} failed: ${res.status} ${res.statusText}\n${body}`,
); );
} }
return res.json() as Promise<T>; return res.json() as Promise<T>;
@@ -51,8 +54,9 @@ export class CurseForgeClient {
headers: this.uploadHeaders(), headers: this.uploadHeaders(),
}); });
if (!res.ok) { if (!res.ok) {
const body = await readErrorBody(res);
throw new Error( throw new Error(
`CurseForge Upload GET ${path} failed: ${res.status} ${res.statusText}`, `CurseForge Upload GET ${path} failed: ${res.status} ${res.statusText}\n${body}`,
); );
} }
return res.json() as Promise<T>; return res.json() as Promise<T>;
@@ -69,8 +73,9 @@ export class CurseForgeClient {
body, body,
}); });
if (!res.ok) { if (!res.ok) {
const resBody = await readErrorBody(res);
throw new Error( throw new Error(
`CurseForge Upload POST ${path} failed: ${res.status} ${res.statusText}`, `CurseForge Upload POST ${path} failed: ${res.status} ${res.statusText}\n${resBody}`,
); );
} }
return res.json() as Promise<T>; return res.json() as Promise<T>;
+6 -2
View File
@@ -1,3 +1,5 @@
import { readErrorBody } from "../utils/fetch";
/** Modrinth API v2 的基础请求客户端,封装鉴权与 User-Agent。 */ /** Modrinth API v2 的基础请求客户端,封装鉴权与 User-Agent。 */
export class ModrinthClient { export class ModrinthClient {
private base = "https://api.modrinth.com/v2"; private base = "https://api.modrinth.com/v2";
@@ -26,8 +28,9 @@ export class ModrinthClient {
headers: this.headers(), headers: this.headers(),
}); });
if (!res.ok) { if (!res.ok) {
const body = await readErrorBody(res);
throw new Error( throw new Error(
`Modrinth API GET ${path} failed: ${res.status} ${res.statusText}`, `Modrinth API GET ${path} failed: ${res.status} ${res.statusText}\n${body}`,
); );
} }
return res.json() as Promise<T>; return res.json() as Promise<T>;
@@ -44,8 +47,9 @@ export class ModrinthClient {
body, body,
}); });
if (!res.ok) { if (!res.ok) {
const resBody = await readErrorBody(res);
throw new Error( throw new Error(
`Modrinth API POST ${path} failed: ${res.status} ${res.statusText}`, `Modrinth API POST ${path} failed: ${res.status} ${res.statusText}\n${resBody}`,
); );
} }
return res.json() as Promise<T>; return res.json() as Promise<T>;
+12
View File
@@ -0,0 +1,12 @@
/**
* 读取错误响应体文本(最多 4096 字符),用于拼入错误信息。
* 若读取失败则返回兜底字符串。
*/
export async function readErrorBody(res: Response): Promise<string> {
try {
const text = await res.text();
return text.slice(0, 4096);
} catch {
return "(unable to read response body)";
}
}