import sharp from 'sharp' import { NextRequest, NextResponse } from 'next/server' import { getServerSession } from 'next-auth' import { authOptions } from '@/lib/auth' const ALLOWED_IMAGE_HOST_SUFFIXES = [ 'alicdn.com', 'taobaocdn.com', 'tbcdn.cn', ] function isAllowedImageHost(hostname: string): boolean { return ALLOWED_IMAGE_HOST_SUFFIXES.some( (suffix) => hostname === suffix || hostname.endsWith(`.${suffix}`), ) } export async function GET(request: NextRequest) { try { const session = await getServerSession(authOptions) if (!session) { return NextResponse.json( { success: false, error: { code: 'UNAUTHORIZED', message: '请先登录后再导出图片', }, }, { status: 401 }, ) } const rawUrl = request.nextUrl.searchParams.get('url') if (!rawUrl) { return NextResponse.json( { success: false, error: { code: 'MISSING_URL', message: '缺少图片地址', }, }, { status: 400 }, ) } let targetUrl: URL try { targetUrl = new URL(rawUrl) } catch { return NextResponse.json( { success: false, error: { code: 'INVALID_URL', message: '图片地址不正确', }, }, { status: 400 }, ) } if (!['http:', 'https:'].includes(targetUrl.protocol) || !isAllowedImageHost(targetUrl.hostname)) { return NextResponse.json( { success: false, error: { code: 'IMAGE_HOST_NOT_ALLOWED', message: '图片来源不允许导出', }, }, { status: 400 }, ) } const upstream = await fetch(targetUrl.toString(), { method: 'GET', cache: 'no-store', headers: { 'User-Agent': 'Mozilla/5.0 Codex Taobao Image Proxy', Referer: 'https://item.taobao.com/', }, }) if (!upstream.ok) { return NextResponse.json( { success: false, error: { code: 'UPSTREAM_IMAGE_FETCH_FAILED', message: `图片下载失败,上游返回 ${upstream.status}`, }, }, { status: 502 }, ) } const buffer = Buffer.from(await upstream.arrayBuffer()) const pngBuffer = await sharp(buffer, { failOn: 'none' }) .flatten({ background: '#ffffff' }) .png() .toBuffer() const metadata = await sharp(pngBuffer).metadata() return new NextResponse(Uint8Array.from(pngBuffer), { status: 200, headers: { 'Content-Type': 'image/png', 'Cache-Control': 'private, max-age=300', 'X-Image-Width': String(metadata.width || 0), 'X-Image-Height': String(metadata.height || 0), }, }) } catch (error) { console.error('[api/taobao-detail-plus/image-proxy] GET error:', error) return NextResponse.json( { success: false, error: { code: 'IMAGE_PROXY_ERROR', message: '图片处理失败,请稍后再试', }, }, { status: 500 }, ) } }