返回

SendGrid邮件发送失败,前端却收到200响应?

php

如何从 Sendgrid.php 文件中获取正确的响应/错误日志?

你是否遇到过使用 SendGrid 发送邮件时,即使发送失败, 前端依然收到 200 响应的情况?本文将为你揭开谜底,并提供解决方案,帮助你准确获取 Sendgrid.php 文件的响应和错误日志。

深入问题:Fetch API 与 HTTP 状态码

问题的根源在于 JavaScript 的 fetch API 处理 HTTP 响应的机制。fetch API 旨在处理网络请求,它关注的是请求是否成功抵达服务器并得到响应,而非响应内容本身是否代表成功。

具体来说,当 fetch 发出请求后:

  • 如果网络连接正常,服务器返回了响应(无论状态码是什么),fetch 都认为请求成功,返回一个 resolved 状态的 Promise。
  • 只有当网络连接中断,例如服务器无法访问,fetch 才会返回一个 rejected 状态的 Promise,表示请求本身失败。

这意味着,即使 SendGrid 服务器返回了 500 Internal Server Error 等错误状态码,fetch 依然会返回一个 resolved 的 Promise,让你误以为邮件发送成功。

解决方案:解析响应状态码

为了获取 SendGrid 发送邮件的真实结果,我们需要检查 fetch 返回的响应对象(Response 对象)中的状态码,而非仅仅依靠 Promise 的状态。

以下是改进后的 JavaScript 代码:

<script>

const remindMeForm = document.getElementById('remindMe');

remindMeForm.addEventListener('submit', function(e) {
    e.preventDefault();
    // ... 获取表单数据 ... 

    fetch('/sendgrid.php', {
        method: 'POST',
        body: formData        
    })
    .then(response => {
        // 检查 HTTP 状态码
        if (response.ok) {
            // 状态码在 200-299 之间,表示成功
            return response.json(); // 假设 sendgrid.php 返回 JSON 格式数据
        } else {
            // 状态码不在 200-299 之间,表示出错
            // 解析错误信息,并抛出 Error 对象,以便在 catch 中处理
            return response.text().then(text => { 
                throw new Error(text); 
            });
        }
    })
    .then(data => {
        // 请求成功,处理响应数据
        console.log('Success:', data);
        jobReminder__message.innerHTML = 'Thank you for your interest in ' + jobTitle + '. A reminder has been scheduled 24 hours from now.';
    })
    .catch(error => {
        // 处理错误
        console.error('Error:', error);
        //  ... 根据错误信息展示相应的提示 ...
    });
} );

</script>

代码解析:

  1. response.ok 属性: Response 对象拥有一个 ok 属性,它是一个布尔值,表示 HTTP 状态码是否在 200299 之间。我们可以利用这个属性判断请求是否真正成功。
  2. 解析错误信息: 如果 response.okfalse,我们需要从响应中解析出错误信息。这里我们使用 response.text() 方法获取响应的文本内容,然后将其包装在一个新的 Error 对象中抛出。
  3. 错误处理: 最后,我们在 catch 块中捕获并处理错误,可以根据错误信息展示相应的提示给用户,或者记录日志供后续分析。

完善后端代码:返回有意义的错误信息

为了让前端能够更好地处理错误,sendgrid.php 也需要做出相应的修改,返回更详细、结构化的错误信息。

<?php
// ... (其他代码)

try {
    $response = $sg->client->mail()->send()->post($request_body);
    
    // 发送成功
    http_response_code(200);
    echo json_encode(['message' => 'Email sent successfully']); 

} catch (Exception $ex) {
    // 发送失败
    http_response_code(500); // 设置为 500 Internal Server Error
    
    // 返回 JSON 格式的错误信息
    echo json_encode([
        'error' => true, //  标记这是一个错误响应
        'message' => 'Failed to send email',
        'details' => $ex->getMessage() //  包含更详细的错误信息
    ]);
}

代码解析:

  1. HTTP 状态码: 使用 http_response_code() 函数设置合适的 HTTP 状态码。发送成功时使用 200,失败时使用 500 或其他合适的错误状态码。
  2. JSON 格式错误信息: 使用 json_encode() 函数将错误信息转换为 JSON 格式,方便前端解析。错误信息中包含 error 字段标记这是一个错误响应,message 字段提供简短的错误,details 字段可以包含更详细的错误信息,例如异常信息。

总结

通过以上修改,你的前端代码将能够正确识别 SendGrid 发送邮件的成功与失败,并根据后端返回的错误信息进行相应的处理。

常见问题解答:

  1. 问:为什么不能直接在第一个 then 中判断状态码?

    答:在第一个 then 中,我们还无法确定响应内容的类型。如果状态码不是 200,我们需要先使用 response.text() 获取错误信息,然后再抛出错误。

  2. 问:response.json()response.text() 有什么区别?

    答:response.json() 用于解析 JSON 格式的响应,response.text() 用于获取响应的文本内容。你需要根据 sendgrid.php 返回的数据类型选择合适的方法。

  3. 问:如何记录错误日志?

    答:你可以在 catch 块中使用 console.error() 将错误信息打印到控制台,或者使用第三方日志库将错误信息记录到文件或数据库中。

  4. 问:如何自定义错误提示信息?

    答:你可以根据后端返回的错误信息,在 catch 块中使用 JavaScript 代码动态生成相应的错误提示信息,例如使用 innerHTML 更新页面元素的内容。

  5. 问:除了 500,还有哪些 HTTP 状态码可以用于表示 SendGrid 发送邮件失败?

    答:除了 500,还有很多 HTTP 状态码可以用于表示 SendGrid 发送邮件失败,例如 400 Bad Request 表示请求参数错误,401 Unauthorized 表示认证失败,429 Too Many Requests 表示请求过于频繁。你需要根据具体情况选择合适的错误状态码。