fix: 修复确认生成报错导致React崩溃 - 递归提取嵌套错误对象
CI/CD Pipeline / Frontend Lint (push) Failing after 36h37m55s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 36h37m55s
CI/CD Pipeline / Production Browser E2E (push) Failing after 1695h12m34s
CI/CD Pipeline / Deploy Production (push) Failing after 1695h12m36s
CI/CD Pipeline / Build Production Runtime Images (push) Failing after 1695h12m38s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (push) Failing after 1695h12m38s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1695h44m3s

- client.ts: safeExtractString 升级为递归版本,处理 {code, message: {code, message}} 嵌套
- GeneratePage.tsx: catch块 extractString 升级为递归版本
- GeneratePage.tsx: 轮询错误路径 safeExtract 递归处理嵌套对象
- GeneratePage.tsx: 渲染处加 typeof 防御,确保不传对象给 React
- 修复 TS2304 变量名错误 (errorMsg → backendMsg)
This commit is contained in:
灵应
2026-07-08 00:16:34 +08:00
parent d541808ce3
commit 6ea650baf5
2 changed files with 57 additions and 24 deletions
+10 -5
View File
@@ -125,14 +125,19 @@ apiClient.interceptors.response.use(
// 注意:后端返回的字段可能是对象 {code, message} 而非字符串,需要安全提取
const data = error.response?.data;
const rawServerMsg = data?.detail || data?.message || data?.msg;
// 安全提取字符串:如果是对象则递归提取 message/msg/detail 字段
// 安全提取字符串:递归处理嵌套对象(后端可能返回 {code, message: {code, message}} 等)
const safeExtractString = (val: unknown): string => {
if (typeof val === "string") return val;
if (typeof val === "object" && val !== null) {
if ("message" in val)
return String((val as { message: unknown }).message);
if ("msg" in val) return String((val as { msg: unknown }).msg);
if ("detail" in val) return String((val as { detail: unknown }).detail);
const obj = val as Record<string, unknown>;
if (typeof obj.message === "string") return obj.message;
if (typeof obj.msg === "string") return obj.msg;
if (typeof obj.detail === "string") return obj.detail;
// 嵌套对象:递归提取
if (typeof obj.message === "object" && obj.message !== null)
return safeExtractString(obj.message);
if (typeof obj.msg === "object" && obj.msg !== null)
return safeExtractString(obj.msg);
return JSON.stringify(val);
}
return "";
+47 -19
View File
@@ -542,15 +542,21 @@ const GeneratePage: React.FC = () => {
(c: { status: string }) => c.status === "failed",
)?.error_message ||
"视频生成失败,请联系管理员或重试";
// 安全提取字符串:如果是对象且有 message 属性,提取 message
const errorMsg =
typeof rawMsg === "string"
? rawMsg
: typeof rawMsg === "object" &&
rawMsg !== null &&
"message" in rawMsg
? String((rawMsg as { message: unknown }).message)
: JSON.stringify(rawMsg);
// 安全提取字符串:递归处理嵌套对象(后端可能返回 {code, message: {code, message}} 等嵌套结构)
const safeExtract = (val: unknown): string => {
if (typeof val === "string") return val;
if (typeof val === "object" && val !== null) {
const obj = val as Record<string, unknown>;
if (typeof obj.message === "string") return obj.message;
if (typeof obj.msg === "string") return obj.msg;
if (typeof obj.detail === "string") return obj.detail;
if (obj.message && typeof obj.message === "object")
return safeExtract(obj.message);
return JSON.stringify(val);
}
return String(val ?? "");
};
const errorMsg = safeExtract(rawMsg);
console.error("[生成失败] planId:", plan.id, "响应:", data);
setGenerateError(errorMsg);
message.error(errorMsg);
@@ -596,15 +602,19 @@ const GeneratePage: React.FC = () => {
};
message?: string;
};
// 安全提取错误消息:后端可能返回对象 {code, message} 而非字符串
// 安全提取错误消息:递归处理嵌套对象(后端可能返回 {code, message: {code, message}} 等)
const extractString = (val: unknown): string => {
if (typeof val === "string") return val;
if (typeof val === "object" && val !== null) {
if ("message" in val)
return String((val as { message: unknown }).message);
if ("msg" in val) return String((val as { msg: unknown }).msg);
if ("detail" in val)
return String((val as { detail: unknown }).detail);
const obj = val as Record<string, unknown>;
if (typeof obj.message === "string") return obj.message;
if (typeof obj.msg === "string") return obj.msg;
if (typeof obj.detail === "string") return obj.detail;
// 嵌套对象:递归提取
if (typeof obj.message === "object" && obj.message !== null)
return extractString(obj.message);
if (typeof obj.msg === "object" && obj.msg !== null)
return extractString(obj.msg);
return JSON.stringify(val);
}
return "";
@@ -622,9 +632,25 @@ const GeneratePage: React.FC = () => {
"完整错误:",
axiosErr,
);
const errorMsg = backendMsg || "生成失败,请检查网络后重试或联系管理员";
setGenerateError(errorMsg);
message.error(errorMsg);
// 确保 errorMsg 一定是字符串(后端可能返回 {code, message} 嵌套对象)
const safeExtractErr = (val: unknown): string => {
if (typeof val === "string") return val;
if (typeof val === "object" && val !== null) {
const obj = val as Record<string, unknown>;
if (typeof obj.message === "string") return obj.message;
if (typeof obj.msg === "string") return obj.msg;
if (typeof obj.detail === "string") return obj.detail;
// 嵌套对象:递归提取
if (typeof obj.message === "object")
return safeExtractErr(obj.message);
return JSON.stringify(val);
}
return String(val ?? "");
};
const finalMsg =
safeExtractErr(backendMsg) || "生成失败,请检查网络后重试或联系管理员";
setGenerateError(finalMsg);
message.error(finalMsg);
}
}, [
title,
@@ -1525,7 +1551,9 @@ const GeneratePage: React.FC = () => {
生成失败
</Text>
<Text style={{ color: "var(--text-secondary)", fontSize: 12 }}>
{generateError}
{typeof generateError === "string"
? generateError
: JSON.stringify(generateError)}
</Text>
</div>
</div>