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

Next.js中表单提交至Mailchimp API时字段映射异常问题

问题分析与修复方案

核心问题

  1. 输入框引用冲突:表单中姓名和邮箱输入框共用了同一个inputRef,提交时firstName和email都获取到最后一个输入框(邮箱)的值,导致后端收到的firstName实际是邮箱地址,最终Mailchimp的FNAME字段被错误填入邮箱。
  2. 校验逻辑错误:后端的!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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 10:45:32