Node.js+Prisma获取表单时出现ObjectID无效的PrismaClientKnownRequestError
解决PrismaClientKnownRequestError: Malformed ObjectID(传入无效ID导致)
问题根源
- 前端异步依赖问题:
useGetBooking是异步请求,初始状态下booking为undefined,此时formId = booking?.form?.id结果为undefined。加上非空断言formId!后,模板字符串会将undefined转为字符串"undefined",导致请求URL变为/users/getForm/undefined。 - 后端校验漏洞:当前端传入字符串
"undefined"时,后端原校验逻辑if (!id || id.length === 0)无法拦截("undefined"是真值且长度不为0),直接进入Prisma查询环节。而Prisma要求MongoDB ObjectID必须是12字节的十六进制字符串,"undefined"不符合格式,触发P2023错误。
解决方案
前端修复:控制请求时机
给useGetForm添加enabled选项,仅当formId有效时才发起请求,同时移除非空断言避免强制传递无效值:
const { id } = useParams<{ id: string }>() const { data: booking } = useGetBooking(id!) const formId = booking?.form?.id // 仅当formId存在时才执行查询 const { data: form } = useGetForm(formId, { enabled: !!formId }) // 同步修改useGetForm,允许id为可选值并在校验后发起请求 export function useGetForm(id?: string) { return useQuery({ queryKey: ['form', id], queryFn: () => { if (!id) throw new Error('Form ID 必填') return getForm({ id }) }, enabled: !!id, }) }
后端修复:加强ID格式校验
除了判断是否为空,新增ObjectID格式校验(12字节十六进制字符串),拦截无效ID:
import { ObjectId } from 'mongodb'; // 或使用Prisma.ObjectId export const getForm = async (req: Request, res: Response) => { try { const { id } = req.params; console.log('form id->', id); // 校验ID是否为空且符合ObjectID格式 if (!id || !ObjectId.isValid(id)) { console.log('id inválido'); return res.status(400).json({ message: "ID inválido." }); } const form = await prisma.form.findUnique({ where: { id }, include: { form_fields: true }, }); if (!form) { return res.status(404).json({ message: "Formulário não encontrado." }); } return res.status(200).json(form); } catch (error) { console.error(error); return res.status(500).json({ message: "Erro ao buscar o formulário." }); } };
额外优化:前端请求前校验
在getForm函数中添加ID格式校验,提前拦截无效请求:
async function getForm({ id }: { id: string }) { if (!id || !/^[0-9a-fA-F]{24}$/.test(id)) { throw new Error('Form ID格式无效') } try { const response = await privateRequest.get(`/users/getForm/${id}`) return response.data } catch (error) { if (isAxiosError(error)) { throw new Error(error.response?.data.message) } else { throw new Error('未知错误') } } }
内容的提问来源于stack exchange,提问作者Cláudio Vitor Dantas
相关产品推荐
相关产品推荐

