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

表单无法调用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" });
  }
}

问题排查与修复方案

核心错误点

  1. req.body重复解析:Next.js API路由会自动解析Content-Type: application/json的请求体,无需再调用JSON.parse(req.body),否则会触发解析错误。
  2. Notion属性格式不匹配API规范:
    • Telefone字段:Notion的number类型直接接收数值,不需要嵌套数组/对象,需转换为有效数字(去除非数字字符)。
    • Empresa等自定义字段:Notion没有名为empresa/end1的属性类型,需匹配数据库实际类型(如rich_text)。
    • select类型字段:必须使用name指定选项值,而非变量名;且不能直接传null,需传空字符串或有效选项。
  3. 错误处理模糊:原代码仅返回通用错误信息,无法定位具体问题,需打印并返回错误详情。

修复后的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 20:36:23