Next.js Server Action报错:无需JSON序列化的解决方法
解决Next.js Server Action "Only plain objects can be passed to Server Functions" 报错
问题根源是你传递了Prisma.Decimal类型的参数,这是自定义类实例,不属于Server Action支持的可自动序列化的普通JS对象(plain objects)。以下是无需全局JSON序列化的处理方案:
方案1:客户端转换类型,服务端转回Decimal
在提交表单时,把Prisma.Decimal转成字符串或数值,服务端接收后再转回Prisma.Decimal:
客户端表单代码修改:
type Ingredient = { name: string; purchasePrice: Prisma.Decimal; } const onSubmit = async (values: Ingredient) => { await addIngredient({ ...values, // 转成字符串(推荐,避免精度丢失) purchasePrice: values.purchasePrice.toString() // 若数值精度要求不高,也可以转成number:values.purchasePrice.toNumber() }) }
服务端ingredient-actions.ts修改:
// 调整参数类型,对应客户端传递的字符串类型 export const addIngredient = async (ingredientData: { name: string; purchasePrice: string; } ): Promise<IngredientPrisma | ErrorMessage> => { try { const ingredientResponse = await prisma.ingredient.create({ data: { name: ingredientData.name, // 把字符串转回Prisma.Decimal purchasePrice: new Prisma.Decimal(ingredientData.purchasePrice) } }); revalidatePath('/dashboard'); return ingredientResponse; } catch (err) { return { message: 'Error creating ingredient' } } }
方案2:表单库层面转换(如React Hook Form)
如果使用React Hook Form这类表单库,可以在字段注册阶段直接转换类型,确保提交的是原生类型:
import { useForm } from 'react-hook-form'; type Ingredient = { name: string; purchasePrice: Prisma.Decimal; } const { register, handleSubmit } = useForm<Ingredient>(); const onSubmit = handleSubmit(async (values) => { await addIngredient(values); }); // 注册purchasePrice字段时自动转换 <input {...register('purchasePrice', { setValueAs: (value) => value.toString() })} />
服务端代码同方案1的修改,接收字符串后转回Decimal即可。
方案3:自定义Server Action序列化规则(全局配置)
Next.js 13.4+支持自定义Server Action的序列化逻辑,可全局处理Prisma.Decimal:
// next.config.js module.exports = { experimental: { serverActions: { serializer: { serialize: (value) => { // 遇到Prisma.Decimal时转成字符串 if (value instanceof Prisma.Decimal) { return value.toString(); } return JSON.stringify(value); }, deserialize: (value) => { const parsed = JSON.parse(value); // 检查并转回Decimal if (parsed.purchasePrice) { parsed.purchasePrice = new Prisma.Decimal(parsed.purchasePrice); } return parsed; } } } } }
此方案为全局配置,会影响所有Server Action,需谨慎使用,优先推荐前两种局部处理方案。
内容的提问来源于stack exchange,提问作者man
相关产品推荐
相关产品推荐

