You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 14:41:01