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
相关产品推荐
相关产品推荐

