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

如何区分Mailchimp API 3.0中两类返回400错误的订阅场景

问题描述

尝试订阅已处于订阅状态的用户时,Mailchimp API返回400错误;但用户退订后再次尝试订阅,同样返回400错误。我需要区分这两种情况,但查看Mailchimp错误文档后发现,400错误对应多种原因(请求错误、无效资源、无效操作、JSON解析异常),无法获取更具体的信息判断是用户已订阅还是已退订。请问如何获取更有用的错误信息?

以下是测试代码:

<?php
$statusMsg = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['subscribe'])) {
  if (!empty($_POST['email']) && !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL) === false) {
    // input sanitation
    array_walk_recursive($_POST, function(&$value) {
      $value = htmlspecialchars(stripslashes(trim($value)));
    });

    $fname = $_POST['fname'];
    $lname = $_POST['lname'];
    $email = $_POST['email'];

    // MailChimp API credentials
    $apiKey = '<my test API key>';
    $listId = '<my list id>';

    // MailChimp API URL
    $dataCenter = substr($apiKey,strpos($apiKey,'-') + 1);
    $url = 'https://' . $dataCenter . '.api.mailchimp.com/3.0/lists/' . $listId . '/members/';

    // member information
    $json = json_encode([
      'email_address' => $email,
      'status' => 'subscribed',
      'merge_fields' => [
        'FNAME' => $fname,
        'LNAME' => $lname
      ]
    ]);

    // send a HTTP POST request with curl
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_USERPWD, 'user:' . $apiKey);
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
    $result = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    // store the status message based on response code
    if ($httpCode == 200) {
      $statusMsg = '<p style="color: #34A853">You have successfully subscribed.</p>';
    } else {
      switch ($httpCode) {
        case 400: // problem: this also happens when user is unsubscribed
          $msg = 'You are already subscribed.';
          break;
        default:
          $msg = 'Some problem occurred, please try again. Error code ' . $httpCode . '.';
          break;
      }
      $statusMsg = '<p style="color: red;">'.$msg.'</p>';
    }
  } else {
    $statusMsg = '<p style="color: red;">Please enter valid email address.</p>';
  }
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Mailchimp API Test</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main>
    <div id="container">
      <h1>Subscribe to our Newsletter</h1>
      <?php echo $statusMsg; ?>
      <form method="post">
        <input type="text" name="subscribe" value="subscribe" aria-hidden="true" readonly hidden>
        <p><label for="fname"> First Name:</label><br>
        <input id="fname" type="text" name="fname" /></p>
        <p><label for="lname"> Last Name:</label><br>
        <input id="lname" type="text" name="lname" /></p>
        <p><label for="email"> Email address:</label><br>
        <input id="email" type="text" name="email" /></p>
        <input type="submit" value="Submit" />
      </form>
    </div>
  </main>
</body>
</html>
解决方案

1. 解析API返回的详细错误响应

Mailchimp的400错误并非只返回状态码,还会在响应体中包含具体错误细节的JSON数据。你的代码目前忽略了$result变量的内容,只需将其解码为数组,即可提取error_code和detail字段来区分不同场景。

修改错误处理逻辑如下:

else {
    // 解析API返回的错误JSON
    $errorData = json_decode($result, true);
    
    switch ($httpCode) {
        case 400:
            $msg = '请求错误,请稍后重试';
            // 提取具体错误码和详情
            if (isset($errorData['errors'][0])) {
                $errorCode = $errorData['errors'][0]['error_code'];
                $errorDetail = $errorData['errors'][0]['detail'];
                
                switch ($errorCode) {
                    case 'ERROR_CONTACT_EXISTS':
                        $msg = '您已处于订阅状态';
                        break;
                    case 'ERROR_CONTACT_UNSUBSCRIBED':
                        $msg = '您已退订,无法通过此方式直接重新订阅,请通过官方渠道手动恢复';
                        break;
                    default:
                        $msg = "请求错误:{$errorDetail}";
                        break;
                }
            }
            break;
        default:
            $msg = "发生未知问题,错误码:{$httpCode}";
            if (isset($errorData['detail'])) {
                $msg .= ",详情:{$errorData['detail']}";
            }
            break;
    }
    $statusMsg = '<p style="color: red;">' . $msg . '</p>';
}

2. 提前查询用户状态(优化方案)

在发起订阅请求前,先调用Mailchimp的会员查询接口,提前获取用户当前状态,避免触发模糊的400错误。接口需要使用邮箱地址的MD5哈希值作为参数:

// 生成邮箱的MD5哈希(需转小写后计算)
$emailHash = md5(strtolower($email));
$checkUrl = "https://{$dataCenter}.api.mailchimp.com/3.0/lists/{$listId}/members/{$emailHash}";

$chCheck = curl_init($checkUrl);
curl_setopt($chCheck, CURLOPT_USERPWD, "user:{$apiKey}");
curl_setopt($chCheck, CURLOPT_RETURNTRANSFER, true);
$checkResult = curl_exec($chCheck);
$checkHttpCode = curl_getinfo($chCheck, CURLINFO_HTTP_CODE);
curl_close($chCheck);

// 根据查询结果处理
if ($checkHttpCode == 200) {
    $memberData = json_decode($checkResult, true);
    switch ($memberData['status']) {
        case 'subscribed':
            $statusMsg = '<p style="color: red;">您已处于订阅状态</p>';
            // 跳过订阅请求
            goto endFormProcessing;
        case 'unsubscribed':
            $statusMsg = '<p style="color: red;">您已退订,请通过官方渠道手动恢复订阅</p>';
            // 跳过订阅请求
            goto endFormProcessing;
        // 可处理其他状态如pending、cleaned等
    }
} elseif ($checkHttpCode != 404) {
    // 查询接口出错,提示用户
    $statusMsg = '<p style="color: red;">查询用户状态失败,请稍后重试</p>';
    goto endFormProcessing;
}

// 原有订阅请求逻辑...

endFormProcessing:
// 后续代码

注意事项

  • 务必处理curl_exec返回false的情况,避免解析空数据导致报错
  • Mailchimp的错误码可能会更新,需以官方最新文档为准
  • 退订用户无法通过API直接恢复订阅,必须由用户手动确认,提示信息需准确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 04:57:32