Next.js中表单提交至Mailchimp API时字段映射异常问题
问题分析与修复方案
核心问题
- 输入框引用冲突:表单中姓名和邮箱输入框共用了同一个
inputRef,提交时firstName和email都获取到最后一个输入框(邮箱)的值,导致后端收到的firstName实际是邮箱地址,最终Mailchimp的FNAME字段被错误填入邮箱。 - 校验逻辑错误:后端的
!firstName && !email条件仅当两个字段都为空时才返回错误,应该改为!firstName || !email,只要任一必填字段为空就拦截请求。
修复后的代码
1. Subscribe表单组件(修改输入框引用)
import { motion } from "framer-motion"; import { useMemo, useRef } from "react"; import getScrollAnimation from "../utils/getScrollAnimation"; import ScrollAnimationWrapper from "./Layouts/ScrollAnimationWrapper"; const Subscribe = () => { const scrollAnimation = useMemo(() => getScrollAnimation(), []); // 给姓名和邮箱分别创建独立ref const nameRef = useRef(null); const emailRef = useRef(null); const subscribeUser = async (e) => { e.preventDefault(); const res = await fetch("/api/subscribeUser", { body: JSON.stringify({ firstName: nameRef.current.value, email: emailRef.current.value, }), headers: { "Content-Type": "application/json", }, method: "POST", }); }; return ( <div> <ScrollAnimationWrapper className="relative w-full mt-16"> <motion.div variants={scrollAnimation} custom={{ duration: 3 }}> <div className="absolute rounded-xl py-8 sm:py-14 px-6 sm:px-12 lg:px-16 w-full flex flex-col sm:flex-row justify-between items-center z-10 bg-white-500"> <div className="flex flex-col text-left w-10/12 sm:w-7/12 lg:w-5/12 mb-6 sm:mb-0"> <h5 className="text-black-600 text-xl sm:text-2xl lg:text-3xl leading-relaxed font-medium"> Subscribe to my newsletter <br />{" "} </h5> <p>I look forward to connecting with you soon</p> </div> <div className="flex flex-col w-10/12 sm:w-5/12 lg:w-7/12"> <form onSubmit={subscribeUser}> <div className="flex flex-row"> <label htmlFor="name-input" className="mb-3 text-sm leading-none text-gray-800" > First name </label> <input type="text" // 修正无效的type="name"为text id="name" name="name" tabIndex={0} ref={nameRef} required aria-label="Enter first name" className="w-54 bg-gray-100 text-sm font-medium leading-none text-gray-800 p-3 border rounded border-gray-200" defaultValue="name" /> </div> <div className="flex flex-row"> <label htmlFor="email-input" className="mb-3 text-sm leading-none text-gray-800" > Email Address </label> <input type="email" id="email" name="email" ref={emailRef} required tabIndex={0} aria-label="Enter email Address" className="w-54 bg-gray-100 text-sm font-medium leading-none text-gray-800 p-3 border rounded border-gray-200" defaultValue="email@gmail.com" /> </div> <button type="submit" value="" name="subscribe"> Send </button> </form> </div> </div> </motion.div> </ScrollAnimationWrapper> </div> ); }; export default Subscribe;
2. subscribeUser后端文件(修复校验逻辑)
import fetch from "isomorphic-unfetch"; export default async (req, res) => { const { firstName, email } = req.body; console.log({ firstName }); console.log({ email }); // 修改校验条件:任一为空则返回错误 if (!firstName || !email) { return res.status(400).json({ error: "Email and name are required" }); } try { const AUDIENCE_ID = process.env.MAILCHIMP_AUDIENCE_ID; const API_KEY = process.env.MAILCHIMP_API_KEY; const DATACENTER = process.env.MAILCHIMP_API_SERVER; const data = { email_address: email, merge_fields: { FNAME: firstName, }, status: "subscribed", }; const response = await fetch( `https://${DATACENTER}.api.mailchimp.com/3.0/lists/${AUDIENCE_ID}/members`, { body: JSON.stringify(data), headers: { Authorization: `apikey ${API_KEY}`, "Content-Type": "application/json", }, method: "POST", } ); if (response.status >= 400) { return res.status(400).json({ error: `There was an error subscribing to the newsletter. Please try again later.`, }); } return res.status(201).json({ error: "" }); } catch (error) { return res.status(500).json({ error: error.message || error.toString() }); } };
额外说明
- 表单中姓名输入框的
type原代码写为name是无效值,已修正为标准的text类型。 - Mailchimp中
merge_fields的FNAME是默认的名字字段标识,需确保你的受众列表中确实存在这个合并字段(若自定义了字段名,需替换为对应的标识)。
内容的提问来源于stack exchange,提问作者1raf
相关产品推荐
相关产品推荐

