Next.js POST请求500内部服务器错误排查求助
Next.js API路由500错误排查与修复
问题核心原因
- 前端未提交
authUserId:表单未携带Supabase用户认证ID,后端解构时authUserId为undefined,导致Supabase数据库操作因缺少查询条件报错。 - Update操作无返回数据:Supabase的
update方法默认不返回更新记录,需添加.select()才能获取有效结果,否则会误判为无用户存在而执行insert,若email已存在则触发唯一约束错误。 - 未处理空值校验:后端未提前校验
authUserId等必填字段,直接执行数据库操作引发报错。
修复步骤
1. 前端补充用户认证ID提交
修改/app/user-profile/page.tsx,获取当前登录用户ID并加入提交数据:
'use client'; import React, { useEffect, useState } from 'react'; import { useForm, SubmitHandler } from 'react-hook-form'; import toast from 'react-hot-toast'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import DeveloperButtons from '@/app/components/DeveloperButtons'; import { supabase } from '@/app/utils/client'; const profileSchema = z.object({ name: z.string().min(1, { message: 'Name is required' }), email: z.string().email({ message: 'Invalid email format' }), age: z.coerce .number() .int() .min(0, { message: 'Invalid age' }) .max(100, { message: 'Invalid age' }), gender: z.string().min(1, { message: 'Gender is required' }), occupation: z.string(), hourly_rate: z.coerce .number() .int() .min(0, { message: 'Invalid hourly rate' }), }); type ProfileFormData = z.infer<typeof profileSchema>; const UserProfile = () => { const [authUserId, setAuthUserId] = useState<string | null>(null); const { register, handleSubmit, reset, formState: { errors }, } = useForm<ProfileFormData>({ resolver: zodResolver(profileSchema), }); // 获取当前登录用户ID useEffect(() => { const getCurrentUser = async () => { const { data: { user } } = await supabase.auth.getUser(); if (user) { setAuthUserId(user.id); } else { toast.error('请先登录'); } }; getCurrentUser(); }, []); const onSubmit: SubmitHandler<ProfileFormData> = async (data) => { if (!authUserId) { toast.error('用户未登录'); return; } const response = await fetch('/api/user-profile/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...data, authUserId }), }); const result = await response.json(); if (response.ok) { toast.success('Profile updated successfully!'); } else { toast.error(result.error || '更新失败'); } }; // 原页面渲染代码保持不变 return ( <div className='container mx-auto p-4'> <DeveloperButtons /> <form onSubmit={handleSubmit(onSubmit)} className='form-control w-full max-w-xs pt-8' > {/* 表单输入项代码保持不变 */} </form> </div> ); }; export default UserProfile;
2. 后端API逻辑优化
修改/app/api/user-profile/route.ts,添加字段校验、优化Supabase操作:
import { NextRequest, NextResponse } from 'next/server'; import { supabase } from '@/app/utils/client'; import { UserProfileUpdateData } from '@/app/types/userProfile'; export async function POST(req: NextRequest) { try { const { authUserId, name, email, age, gender, occupation, hourly_rate, }: UserProfileUpdateData = await req.json(); // 校验必填字段 if (!authUserId || !email) { return NextResponse.json( { error: 'authUserId和email为必填项' }, { status: 400 } ); } // 添加.select()获取更新后的记录 const { data: updateData, error: updateError } = await supabase .from('users') .update({ name, email, age, gender, occupation, hourly_rate }) .eq('auth_user_id', authUserId) .select(); if (updateError) throw updateError; // 无更新记录则执行插入 if (!updateData || updateData.length === 0) { const { error: insertError } = await supabase.from('users').insert([ { auth_user_id: authUserId, name, email, age, gender, occupation, hourly_rate, number_of_active_projects: 0, number_of_completed_projects: 0, }, ]); if (insertError) throw insertError; return NextResponse.json({ message: '用户资料创建成功' }, { status: 201 }); } return NextResponse.json({ message: '用户资料更新成功' }, { status: 200 }); } catch (error: any) { return NextResponse.json( { error: error.message || '服务器内部错误' }, { status: 500 } ); } }
3. 额外检查项
- 确认
utils/client.ts中的Supabase客户端配置正确,已设置NEXT_PUBLIC_SUPABASE_URL和NEXT_PUBLIC_SUPABASE_ANON_KEY环境变量。 - 检查Supabase控制台「权限」面板,确保anon用户拥有
users表的insert和update权限。 - 查看Supabase控制台「日志」面板,获取具体数据库错误信息辅助排查。
内容的提问来源于stack exchange,提问作者TheSnowmann
相关产品推荐
相关产品推荐

