Skip to content

Commit e7896a6

Browse files
committed
fix: 修复 MDX 本地图片渲染为 [object Object] 及建议接口 JSON 解析失败
- mdx-components: remark-image 把本地相对路径图片编译成静态 import, src 是 StaticImageData 对象,原生 <img> 直接透传导致 src="[object Object]", 文档内本地图片全部裂图,并触发大量 /docs/.../[object Object] 404 - /api/suggestions: 归一化 key 后的全角冒号与缺失引号;整体 JSON.parse 失败时逐个提取对象,兼容编号列表、多数组拼接等 LLM 输出 - docs/resolve: 后端 404(无历史映射)是正常结论,不再按 error 记录; 403 / 5xx 仍记录 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014zBGrQgQnx1eLA9jQfSJWD
1 parent fc5a1da commit e7896a6

3 files changed

Lines changed: 33 additions & 3 deletions

File tree

‎app/[locale]/docs/[...slug]/page.tsx‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ async function resolveDocPath(
6363
}
6464
return null;
6565
}
66-
// 非 3xx:记录真实状态,便于从 Vercel 日志定位(CF 403 / 后端异常等)
66+
// 404 = 后端无历史映射,是正常的"真 404"结论,不算故障
67+
if (res.status === 404) return null;
68+
// 其余非 3xx:记录真实状态,便于从 Vercel 日志定位(CF 403 / 后端异常等)
6769
console.error("[docs/resolve] non-redirect status", {
6870
path: strippedPath,
6971
status: res.status,

‎app/api/suggestions/route.ts‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,34 @@ export async function POST(req: Request) {
159159

160160
// 修复大模型可能生成的中文引号
161161
cleanedText = cleanedText.replace(/“/g, '"').replace(/”/g, '"');
162+
// 修复 key 后的全角冒号 / 冒号被包进引号,如 "action:"xx" 或 "action:"xx"
163+
cleanedText = cleanedText.replace(
164+
/"(title|label|action)"?\s*[::]\s*"/g,
165+
'"$1":"',
166+
);
162167

163168
// 尝试仅提取数组部分,防止 AI 返回了前缀描述文本
164169
const arrayMatch = cleanedText.match(/\[[\s\S]*\]/);
165170
if (arrayMatch) {
166171
cleanedText = arrayMatch[0];
167172
}
168173

169-
questions = JSON.parse(cleanedText);
174+
try {
175+
questions = JSON.parse(cleanedText);
176+
} catch (parseError) {
177+
// 编号列表 / 多个数组拼接等非法外壳:逐个提取对象
178+
const objects = (cleanedText.match(/\{[^{}]*\}/g) ?? []).flatMap(
179+
(chunk) => {
180+
try {
181+
return [JSON.parse(chunk)];
182+
} catch {
183+
return [];
184+
}
185+
},
186+
);
187+
if (objects.length === 0) throw parseError;
188+
questions = objects;
189+
}
170190
} catch (e) {
171191
console.error("解析建议 JSON 失败:", e, "原始文本:", text);
172192

‎mdx-components.tsx‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,15 @@ export function getMDXComponents(components?: MDXComponents): MDXComponents {
3030
return {
3131
...defaultMdxComponents,
3232
// 覆盖默认的 img 映射,使用原生 <img> 标签而不是 Next.js Image 组件
33-
img: (props) => <img {...props} alt={props.alt || ""} />,
33+
// 本地相对路径图片会被 remark-image 编译成静态 import,src 是
34+
// StaticImageData 对象而不是字符串,直接透传会渲染成 "[object Object]"
35+
img: ({ src, ...props }) => {
36+
const resolved =
37+
src && typeof src === "object" && "src" in src
38+
? (src as { src: string }).src
39+
: src;
40+
return <img {...props} src={resolved} alt={props.alt || ""} />;
41+
},
3442
...components,
3543
};
3644
}

0 commit comments

Comments
 (0)