表单无法调用Next.js动态API更新Notion数据库:500错误
问题:Next.js API对接Notion数据库提交表单返回500内部服务器错误
我正在尝试通过Next.js API对接Notion API,将网站表单数据同步至Notion数据库。表单用Formik处理数据,Chakra-UI的toast组件展示提交反馈,提交时通过动态路由${urlPath}/api/submit/${title}发送POST请求,但控制台返回500内部服务器错误。已经给Notion集成开启全部内容权限,调整用户权限后问题仍未解决。
表单组件代码
import {useToast} from '@chakra-ui/react' import PropTypes from 'prop-types' import {useState} from 'react' import FormPageStructure from './formPageStructure' import {Form, Formik, Field} from 'formik' function FormRenderer (props) { const { title, fields, buttonLabel, successMessage, errorMessage } = props const [serverState, setServerState] = useState() const toast = useToast() const handleServerResponse = (ok, msg) => { setServerState({ok, msg}) toast({ title: ok ? 'Mensagem enviada' : 'Erro ao enviar mensagem', description: msg, status: ok ? 'success' : 'error', duration: 9000, isClosable: true }) } const urlPath = process.env.NODE_ENV === 'production' ? process.env.URL : 'http://localhost:3000' const usoArr = fields.filter(({fieldName}) => fieldName === 'uso') const atuaçãoArr = fields.filter(({fieldName}) => fieldName === 'atuação') const submitForm = async values => { const res = await fetch(`${urlPath}/api/submit/${title}`, { method: 'POST', body: JSON.stringify(values, null, 2), headers: {'Content-Type': 'application/json'} }) if (res.status === 201) { handleServerResponse(true, successMessage) } else { handleServerResponse(false, errorMessage) } } const initialValues = { nome: '', email: '', tel: '', empresa: '', mensagem: '', atuação: '', uso: '' } return ( <FormPageStructure {...props}> <Formik initialValues={initialValues} name={title} onSubmit={submitForm} > <Form name={title}> <label htmlFor="nome"> Nome <Field type="text" name="nome" /> </label> <label htmlFor="email"> Email <Field type="email" name="email" /> </label> <label htmlFor="tel"> Telefone <Field type="tel" name="tel" /> </label> <label htmlFor="empresa"> Empresa <Field type="text" name="empresa" /> </label> <label htmlFor="atuação"> Atuação <Field name="atuação" as="select"> {atuaçãoArr[0].options.map((option, i) => ( <option key={i} value={option}> {option} </option> ))} </Field> </label> <label htmlFor="uso"> Uso <Field name="uso" as="select"> {usoArr[0].options.map((option, i) => ( <option key={i} value={option}> {option} </option> ))} </Field> </label> <label htmlFor="mensagem"> <Field as="textarea" name="mensagem" /> </label> <button type="submit">{buttonLabel || 'Enviar'}</button> </Form> </Formik> </FormPageStructure> ) } FormRenderer.propTypes = { backgroundImage: PropTypes.object, backgroundImageSm: PropTypes.object, title: PropTypes.string, formHeadline: PropTypes.string, formTagline: PropTypes.array, formInfo: PropTypes.array, fields: PropTypes.array, buttonLabel: PropTypes.string, successMessage: PropTypes.string, errorMessage: PropTypes.string, privacyMessage: PropTypes.string } export default FormRenderer
原API处理函数代码
const { Client } = require('@notionhq/client'); const notion = new Client({ auth: process.env.NOTION_TOKEN }); export default async function postInfo(req, res) { const { slug } = req.query; const formName = slug[0]; /* Logic for url pushing: .../api/submit/formName/ -> tags form @ notion db */ if (req.method !== 'POST') { return res .status(405) .json({ message: `Method ${req.method} not allowed` }); } try { const { nome, email, tel, empresa, mensagem, atuação, uso, end1, end2, cep, cidade } = JSON.parse(req.body); await notion.pages.create({ parent: { database_id: process.env.NOTION_DATABASE_ID }, properties: { Nome: { title: [ { text: { content: nome, }, }, ], }, Email: { email: email }, Telefone: { number: [ { number: { content: tel } } ] }, Empresa: { empresa: empresa }, 'Área de atuação': { select: { atuação: atuação } }, 'Tipo de uso': { select: { uso: uso } }, Mensagem: { rich_text: [ { text: { content: mensagem } } ] }, 'Endereço 1': { end1: end1 }, 'Endereço 2': { end2: end2 }, CEP: { cep: cep }, Cidade: { cidade: cidade }, Formulário: { select: formName || null } }, }); res.status(201).json({ message: 'Form submitted successfully' }); } catch (error) { res.status(500).json({ message: "there was an error" }); } }
问题排查与修复方案
核心错误点
- req.body重复解析:Next.js API路由会自动解析
Content-Type: application/json的请求体,无需再调用JSON.parse(req.body),否则会触发解析错误。 - Notion属性格式不匹配API规范:
Telefone字段:Notion的number类型直接接收数值,不需要嵌套数组/对象,需转换为有效数字(去除非数字字符)。Empresa等自定义字段:Notion没有名为empresa/end1的属性类型,需匹配数据库实际类型(如rich_text)。select类型字段:必须使用name指定选项值,而非变量名;且不能直接传null,需传空字符串或有效选项。
- 错误处理模糊:原代码仅返回通用错误信息,无法定位具体问题,需打印并返回错误详情。
修复后的API处理函数代码
const { Client } = require('@notionhq/client'); const notion = new Client({ auth: process.env.NOTION_TOKEN }); export default async function postInfo(req, res) { const { slug } = req.query; const formName = slug[0]; if (req.method !== 'POST') { return res.status(405).json({ message: `Method ${req.method} not allowed` }); } try { // 直接使用已解析的req.body const { nome, email, tel, empresa, mensagem, atuação, uso, end1, end2, cep, cidade } = req.body; await notion.pages.create({ parent: { database_id: process.env.NOTION_DATABASE_ID }, properties: { Nome: { title: [ { text: { content: nome || '', }, }, ], }, Email: { email: email || '' }, Telefone: { // 清理非数字字符并转换为数字,空值则传null number: tel ? Number(tel.replace(/\D/g, '')) : null }, Empresa: { // 假设数据库中Empresa为rich_text类型 rich_text: [{ text: { content: empresa || '' } }] }, 'Área de atuação': { select: { name: atuação || '' } }, 'Tipo de uso': { select: { name: uso || '' } }, Mensagem: { rich_text: [ { text: { content: mensagem || '' } } ] }, 'Endereço 1': { rich_text: [{ text: { content: end1 || '' } }] }, 'Endereço 2': { rich_text: [{ text: { content: end2 || '' } }] }, CEP: { rich_text: [{ text: { content: cep || '' } }] }, Cidade: { rich_text: [{ text: { content: cidade || '' } }] }, Formulário: { select: { name: formName || '' } } }, }); res.status(201).json({ message: 'Form submitted successfully' }); } catch (error) { // 打印错误到控制台方便排查 console.error('Notion API Error:', error); res.status(500).json({ message: "提交失败", error: error.message }); } }
内容的提问来源于stack exchange,提问作者Eduardo Oliveira
相关产品推荐
相关产品推荐

