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

NextJS 14生产环境API接口404,本地运行正常

NextJS 14生产环境/api/sendEmail接口404问题排查

我用NextJS 14搭建了一个小型网站,包含联系我们页面。在GetInTouch.tsx中基于Formik实现了表单验证与提交逻辑,提交时调用/api/sendEmail接口;pages/api目录下有sendEmail.ts文件,使用Mailtrap发送邮件。本地测试时表单验证和邮件发送均正常,但部署到生产环境后,始终提示mydomain.com/api/sendEmail不存在,作为NextJS新手无法定位问题所在。

GetInTouch.tsx代码

<Formik
  initialValues={{
    fullName: "",
    phoneNumber: "",
    email: "",
    message: "",
  }}
  validationSchema={Yup.object({
    fullName: Yup.string().required("Required"),
    phoneNumber: Yup.string().required("Required"),
    email: Yup.string()
      .email("Invalid email address")
      .required("Required"),
    message: Yup.string().required("Required"),
  })}
  onSubmit={async (values, { setSubmitting, resetForm }) => {
    try {
      const response = await fetch("/api/sendEmail", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(values),
      });

      if (!response.ok) {
        throw new Error("Failed to send email");
      }

      setShowSuccessMessage(true);
      setTimeout(() => {
        setShowSuccessMessage(false);
      }, 5000);

      resetForm();
    } catch (error) {
      console.error("Error sending email:", error);
    } finally {
      setSubmitting(false);
    }
  }}
>
  {(formik) => (
    <Form>
      <div className="pb-3">
        <Field 
          type="text"
          name="fullName"
          placeholder="Full Name"
          className="form-input space-y-2 pt-15px lg:pt-20px w-full h-12 px-5 py-10px placeholder-white text-white"
          style={{ backgroundColor: '#0c3863',border: '1.5px solid white'}}
        />
        <ErrorMessage
          name="fullName"
          component="div"
          className="text-red-600"
          style={{color: "red"}}
        />
      </div>
      <div className="pb-3">
        <Field
          type="text"
          name="phoneNumber"
          placeholder="Phone Number"
          className="form-input space-y-2 pt-15px lg:pt-20px w-full h-12 px-5 py-10px placeholder-white text-white "
          style={{ backgroundColor: '#0c3863',border: '1.5px solid white'}}
        />
        <ErrorMessage
          name="phoneNumber"
          component="div"
          className="text-red-600"
          style={{color: "red"}}
        />
      </div>
      <div className="pb-3">
        <Field
          type="email"
          name="email"
          placeholder="Email"
          className="form-input space-y-2 pt-10px lg:pt-15px w-full h-12 px-5 py-10px placeholder-white text-white"
          style={{ backgroundColor: '#0c3863',border: '1.5px solid white'}}
        />
        <ErrorMessage
          name="email"
          component="div"
          className="text-red-600"
          style={{color: "red"}}
        />
      </div>
      <div className="pb-3">
        <Field
          as="textarea"
          name="message"
          placeholder="Message"
          className="form-textarea w-full pt-15px lg:pt-20px placeholder-white px-5 py-30px text-white" 
          style={{ backgroundColor: '#0c3863',border: '1.5px solid white'}}
        />
        <ErrorMessage
          name="message"
          component="div"
          className="text-red-600"
          style={{color: "red"}}
        />
      </div>
      <Button
        type="submit"
        disabled={formik.isSubmitting}
        className="btn"
        size={"large"} colorTheme={"blue1"} uppercase
      >
        Enquire now
      </Button>
    </Form>
  )}
</Formik>

{showSuccessMessage && (
  <div className="success-message flex items-center text-white text-sm font-bold py-3" >
    Message sent successfully!
  </div>
)}
</div>

sendEmail.ts代码

import { NextApiRequest, NextApiResponse } from 'next';
import nodemailer from 'nodemailer';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method !== 'POST') {
    return res.status(405).end(); // Method Not Allowed
  }

  try {
    const { fullName, phoneNumber, email, message } = req.body;

    const transporter = nodemailer.createTransport({
      host: 'sandbox.smtp.mailtrap.io',
      port: 2525,
      auth: {
        user: '543c2217cf0f8b',
        pass: '5rthae759cd4c0',
      },
    });

    await transporter.sendMail({
      from: 'your-email@example.com',
      to: 'support@abc.com',
      subject: 'New contact form submission',
      html: `
        <p>Full Name: ${fullName}</p>
        <p>Phone Number: ${phoneNumber}</p>
        <p>Email: ${email}</p>
        <p>Message: ${message}</p>
      `,
    });

    res.status(200).json({ message: 'Email sent successfully' });
  } catch (error) {
    console.error('Error sending email:', error);
    res.status(500).json({ error: 'An error occurred while sending the email' });
  }
}

问题排查与解决办法

  • 路由目录不匹配:NextJS 14默认推荐App Router,若你用的是App Router模式,API路由需放在app/api/sendEmail/route.ts(文件名必须是route.ts),且导出方式要调整为App Router的格式:
    import { NextResponse } from 'next/server';
    import nodemailer from 'nodemailer';
    
    export async function POST(request: Request) {
      const body = await request.json();
      const { fullName, phoneNumber, email, message } = body;
    
      const transporter = nodemailer.createTransport({
        host: 'sandbox.smtp.mailtrap.io',
        port: 2525,
        auth: {
          user: '543c2217cf0f8b',
          pass: '5rthae759cd4c0',
        },
      });
    
      await transporter.sendMail({
        from: 'your-email@example.com',
        to: 'support@abc.com',
        subject: 'New contact form submission',
        html: `
          <p>Full Name: ${fullName}</p>
          <p>Phone Number: ${phoneNumber}</p>
          <p>Email: ${email}</p>
          <p>Message: ${message}</p>
        `,
      });
    
      return NextResponse.json({ message: 'Email sent successfully' }, { status: 200 });
    }
    
  • 部署平台静态导出限制:若你在next.config.js中配置了output: 'export'做静态导出,NextJS不会生成API路由,因为静态站点不支持服务器端逻辑。此时需去掉静态导出配置,或改用部署平台的Serverless函数替代NextJS API路由。
  • 路径大小写敏感:生产环境服务器通常区分文件名大小写,确保sendEmail.ts的文件名与请求路径/api/sendEmail完全一致(比如不要写成SendEmail.ts)。
  • basePath配置影响:若next.config.js中设置了basePath,请求API时需带上basePath,可通过环境变量动态拼接路径:
    const apiUrl = `${process.env.NEXT_PUBLIC_BASE_PATH || ''}/api/sendEmail`;
    const response = await fetch(apiUrl, { /* 其余配置 */ });
    
  • 缓存问题:生产环境可能缓存了旧页面资源,强制刷新浏览器(Ctrl+Shift+R)或重新部署项目,确保最新代码生效。

内容的提问来源于stack exchange,提问作者user3391363

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 05:55:16