From 4fe91d442ed1c5f05d412badcce7b52f239021f9 Mon Sep 17 00:00:00 2001 From: 134 Date: Thu, 11 Jun 2026 17:06:21 +0800 Subject: [PATCH] Improve canvas image download fallback --- app/api/canvas/download-image/route.ts | 48 ++++++++++++++++++++------ components/canvas/nodes/ImageNode.tsx | 34 +++++++++++------- 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/app/api/canvas/download-image/route.ts b/app/api/canvas/download-image/route.ts index 1ab6fc296..e1e50363b 100644 --- a/app/api/canvas/download-image/route.ts +++ b/app/api/canvas/download-image/route.ts @@ -30,6 +30,21 @@ function resolveDownloadUrl(rawUrl: unknown, origin: string): string { } } +function resolveDownloadUrls(body: Record, origin: string): string[] { + const rawCandidates = Array.isArray(body.urls) ? body.urls : [body.url]; + const urls: string[] = []; + const seen = new Set(); + + for (const rawUrl of rawCandidates) { + const url = resolveDownloadUrl(rawUrl, origin); + if (!url || seen.has(url)) continue; + seen.add(url); + urls.push(url); + } + + return urls.slice(0, 6); +} + export async function POST(request: NextRequest) { try { const session = await auth(); @@ -39,23 +54,34 @@ export async function POST(request: NextRequest) { const body = (await request.json().catch(() => ({}))) as Record; const requestOrigin = getRequestOrigin(request); - const url = resolveDownloadUrl(body.url, requestOrigin); - if (!url) { + const urls = resolveDownloadUrls(body, requestOrigin); + if (urls.length === 0) { return NextResponse.json({ success: false, error: "图片地址无效" }, { status: 400 }); } const name = sanitizeCanvasDownloadFileName(String(body.name || ""), "canvas-image"); - const result = await fetchCanvasDownloadAsset({ - file: { url, name }, - index: 0, - requestOrigin, - cookie: request.headers.get("cookie") || "", - includeSequencePrefix: false, - }); + const cookie = request.headers.get("cookie") || ""; + let result: Awaited> | null = null; + const failures: string[] = []; - if (!result.ok) { + for (const url of urls) { + result = await fetchCanvasDownloadAsset({ + file: { url, name }, + index: 0, + requestOrigin, + cookie, + includeSequencePrefix: false, + }); + if (result.ok) break; + failures.push(`${url}: ${result.error}`); + } + + if (!result?.ok) { + if (failures.length > 0) { + console.warn("[CanvasDownloadImage] All candidates failed:", failures); + } return NextResponse.json( - { success: false, error: result.error || "图片下载失败" }, + { success: false, error: result?.error || "图片源文件暂时不可访问" }, { status: 502 } ); } diff --git a/components/canvas/nodes/ImageNode.tsx b/components/canvas/nodes/ImageNode.tsx index b8e23c9fa..01a2c998f 100644 --- a/components/canvas/nodes/ImageNode.tsx +++ b/components/canvas/nodes/ImageNode.tsx @@ -7383,6 +7383,21 @@ export function ImageNode({ const handleDownload = async () => { if (!data.src) return; const originalUrl = String(resolveOriginalImageUrl(data.src) || data.src || "").trim(); + const downloadCandidates = Array.from( + new Set( + [ + originalUrl, + data.src, + displayImageSrc, + fullscreenPreviewSrc, + buildImageProxyUrl(originalUrl || data.src || "", { + delivery: "proxy", + }), + ] + .map((value) => String(value || "").trim()) + .filter(Boolean) + ) + ); if (!originalUrl) { toast.error("下载失败,请重试"); return; @@ -7397,7 +7412,8 @@ export function ImageNode({ "Content-Type": "application/json", }, body: JSON.stringify({ - url: originalUrl, + url: downloadCandidates[0], + urls: downloadCandidates, name: displayTitle, }), }); @@ -7434,17 +7450,11 @@ export function ImageNode({ toast.success("下载成功"); } catch (error) { console.error("下载失败:", error); - try { - triggerBrowserDownload(originalUrl, undefined, { openInNewTab: true }); - toast.message( - error instanceof Error - ? `${error.message},已打开原图,可稍后重试标准 PNG 下载` - : "标准 PNG 下载失败,已打开原图,可稍后重试" - ); - } catch (openError) { - console.error("打开原图失败:", openError); - toast.error("下载失败,请重试"); - } + toast.error( + error instanceof Error + ? `${error.message},源图可能已失效,请稍后重试或重新生成图片` + : "图片源文件暂时不可访问,请稍后重试或重新生成图片" + ); } };