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

Axios PUT请求添加SendGrid联系人返回500错误问题排查

SendGrid邮件列表订阅500错误修复方案

你的代码存在3个直接触发错误的逻辑问题,逐个修复即可:

定位到的具体故障

  • 前端传参格式错误:直接将mail字符串作为Axios PUT的请求体发送,Axios不会自动将字符串包装为JSON对象,后端req.body.mail取值为undefined,传给SendGrid的邮箱参数为空。
  • 前端响应取值错误:Axios请求成功的回调中,响应数据直接存在result.data路径下,你写的result.response.data是错误回调里才有的属性,请求成功后执行到这行直接抛JS异常。
  • 后端变量作用域冲突:Next.js接口的响应对象命名为res,SendGrid请求的then回调中又将返回值命名为res,内层变量覆盖外层服务端响应对象,调用res.status()时实际操作的是SendGrid返回的响应对象,根本没有status()方法,直接触发服务端异常返回500。另外你在catch块中没有打印SendGrid返回的真实错误信息,所有报错被吞掉,无法定位具体原因。
  • 额外安全风险:你把SendGrid API Key存在NEXT_PUBLIC_前缀的环境变量中,这类变量会被打包到前端JS里,任何人都能拿到你的API Key操作你的SendGrid账号,必须立刻更换。

修正后代码

前端Hero组件

const Hero = () => {
  // 邮箱初始值设为空字符串,不要用null
  const [mail, setMail] = useState("");
  const [loading, setLoading] = useState(false);
  
  const subscribe = () => {
    // 基础空值校验
    if (!mail.trim()) {
      toast.error("请输入邮箱地址");
      return;
    }
    setLoading(true);
    // 传参包装为对象,和后端req.body.mail对应
    axios.put("/api/sendgrid/mailingList", { mail })
      .then((result) => {
        if (result.status === 200) {
          // 正确读取响应数据
          toast.success(result.data.message);
          setMail("");
          setLoading(false);
        }
      })
      .catch((error) => {
        console.log(error.response?.data);
        toast.error(error.response?.data?.message || "订阅失败,请稍后重试");
        setLoading(false);
      });
  };

  return (
    {/* 其余Hero组件内容 */}
    <input
      type="email"
      value={mail}
      // 必须绑定输入事件更新mail状态,之前的代码片段里缺失这部分
      onChange={(e) => setMail(e.target.value)}
      placeholder="输入邮箱订阅更新"
    />
    <button onClick={subscribe} disabled={loading}>
      {loading ? "提交中..." : "立即订阅"}
    </button>
    {/* 其余Hero组件内容 */}
  )
}

后端接口(/api/sendgrid/mailingList.js)

import axios from "axios";
 
export default async function handler(req, res) {
  // 非PUT请求直接拦截
  if (req.method !== "PUT") {
    return res.status(405).send({ message: "不支持的请求方法" });
  }

  try {
    const { mail } = req.body;
    if (!mail) {
      return res.status(400).send({ message: "邮箱参数不能为空" });
    }

    // SendGrid请求响应命名为sgRes,避免和外层服务端res变量冲突
    const sgRes = await axios.put(
      "https://api.sendgrid.com/v3/marketing/contacts",
      {
        contacts: [{ email: mail }],
        list_ids: [process.env.SENDGRID_MAILING_ID],
      },
      {
        headers: {
          "Content-Type": "application/json",
          // 使用服务端私有环境变量存储API Key,不要加NEXT_PUBLIC前缀
          Authorization: `Bearer ${process.env.SENDGRID_API_KEY}`,
        },
      }
    );

    return res.status(200).send({
      message: "你的邮箱已成功加入邮件列表,欢迎 👋",
    });
  } catch (error) {
    // 本地调试时打印真实错误,方便排查权限、列表ID配置等问题
    console.error("订阅请求失败:", error.response?.data || error.message);
    return res.status(500).send({
      message: "订阅出现问题,请稍后重试或联系管理员",
    });
  }
}

后续配置注意事项

  • 废弃当前暴露在前端的SendGrid API Key,在SendGrid后台重新生成新的密钥,存在不带NEXT_PUBLIC_前缀的服务端环境变量中。
  • 确认SENDGRID_MAILING_ID配置正确,API Key开启了营销联系人管理的对应权限。
  • 可增加邮箱格式正则校验,过滤无效邮箱地址减少接口报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:27:24