Next.js13保存图片时API路由返回500错误(Prisma+Zod)
问题
我正在开发一个Next.js应用,用户可生成Logo并保存至账户。点击“Save Image”按钮时,会向API路由发送POST请求,将图片URL和用户ID保存到Prisma数据库。
目前遇到的问题是:点击按钮后浏览器控制台出现500错误,图片无法保存。我检查了API路由实现和Prisma schema,但未找到错误原因。
前端代码(DisplayLogo组件)
'use client'; import { PageWrapper } from '@/components/Page-Wrapper'; import Image from 'next/image'; import { useRouter, useSearchParams } from 'next/navigation'; import React, { useEffect, useState } from 'react'; import { useMutation } from '@tanstack/react-query'; import axios from 'axios'; import { toast } from '@/hooks/use-toast'; import { Button } from '@/components/ui/button'; const DisplayLogo: React.FC = () => { const [image, setImage] = useState<string | null>(null); const searchParams = useSearchParams(); const router = useRouter(); useEffect(() => { const imageQueryParam = searchParams?.get('image'); if (typeof imageQueryParam === 'string') { setImage(imageQueryParam); } }, [searchParams]); const createImageMutation = useMutation( async ({ imageUrl }: { imageUrl: string }) => { await axios.post('/api/save-image', { imageUrl }); }, { onError: () => { toast({ title: 'Something went wrong', description: 'Could not save image. Please try again later.', variant: 'destructive', }); }, onSuccess: () => { toast({ title: 'Image saved', description: 'Your image has been saved to your account', variant: 'default', }); }, } ); const handleSaveImage = () => { if (image) { createImageMutation.mutate({ imageUrl: image }); } }; return ( <PageWrapper> <main className='py-40 px-8 md:px-12 lg:px-24 flex flex-col items-center justify-center'> <h1 className='text-3xl md:text-4xl lg:text-5xl font-bold mb-4'> Your Generated Image </h1> {image ? ( <div className='mt-8'> <Image className='w-64 h-64 object-cover rounded-md shadow-lg' src={image} alt='AI Generated' width={500} height={500} /> </div> ) : ( <p className='text-center text-lg mx-auto max-w-md mb-8'> No logo image found. Please go back and generate an image first. </p> )} <div className='flex flex-col items-center mt-5'> {image && <Button onClick={handleSaveImage}>Save Image</Button>} <p className='text-center text-lg mx-auto max-w-md mt-5'> Congratulations! Your ai generated has been generated using the input you provided! </p> </div> </main> </PageWrapper> ); }; export default DisplayLogo;
API路由代码(/api/save-image)
// Import the required modules and types import { db } from '@/lib/db'; import { getAuthSession } from '@/lib/auth'; import { ImageValidator } from '@/lib/validators/images'; import { z } from 'zod'; export async function POST(req: Request) { try { const session = await getAuthSession(); if (!session?.user) { return new Response('Unauthorized', { status: 401 }); } const body = await req.json(); const { imageUrl } = ImageValidator.parse(body); // Check if the image already exists const image = await db.image.findUnique({ where: { id: imageUrl, }, }); if (image) { return new Response('Image already exists', { status: 409 }); } // Create the image and associate it with the user const newImage = await db.image.create({ data: { userId: session.user.id, url: imageUrl, createdAt: new Date(), }, }); return new Response(JSON.stringify({ message: 'Image saved successfully' }), { status: 201, headers: { 'Content-Type': 'application/json' }, }); } catch (error) { if (error instanceof z.ZodError) { return new Response(error.message, { status: 422 }); } return new Response('Something went wrong', { status: 500 }); } }
Zod验证Schema
import { z } from 'zod'; export const ImageValidator = z.object({ imageUrl: z.string().url(), userId: z.string().optional(), createdAt: z.date().optional(), updatedAt: z.date().optional(), }); export type ImageData = z.infer<typeof ImageValidator>;
错误截图


排查与解决建议
核心问题:存在性查询条件错误
API中用db.image.findUnique({ where: { id: imageUrl } }),但Prisma模型的id通常是UUID或自增ID,不是图片URL。这会导致数据库查询失败,抛出500错误。
解决:修改为按url字段查询:const image = await db.image.findUnique({ where: { url: imageUrl, }, });同时确保Prisma Schema中
Image模型的url字段设置了unique: true,避免重复保存。补充错误日志定位问题
当前代码只捕获Zod错误,其他数据库、会话相关错误直接返回500,无法看到具体原因。在catch块添加日志打印:catch (error) { if (error instanceof z.ZodError) { return new Response(error.message, { status: 422 }); } console.error('Save image error:', error); // 打印到服务器控制台 return new Response('Something went wrong', { status: 500 }); }这样可以在本地开发服务器或Vercel控制台看到具体错误信息,比如Prisma字段不匹配、数据库连接问题等。
优化前端错误提示
前端可以根据响应状态码区分错误类型,给用户更精准提示:onError: (error) => { if (error.response?.status === 422) { toast({ title: '无效URL', description: '图片URL格式不正确,请检查后重试。', variant: 'destructive', }); } else if (error.response?.status === 409) { toast({ title: '图片已存在', description: '该图片已经保存到你的账户中。', variant: 'destructive', }); } else { toast({ title: '保存失败', description: '图片保存失败,请稍后重试。', variant: 'destructive', }); } },检查Prisma Schema匹配性
确认Image模型字段与API中创建数据的字段一致,示例Schema:model Image { id String @id @default(uuid()) url String @unique userId String user User @relation(fields: [userId], references: [id]) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }若
createdAt已设默认值,API中无需手动传递createdAt: new Date(),由数据库自动生成即可。
内容的提问来源于stack exchange,提问作者Brayan Cuenca
相关产品推荐
相关产品推荐

