包含PHPMailer函数时Webhook调用失败问题求助
问题分析与解决方案
核心矛盾:手动访问complete.php完全正常,但Webhook通过curl调用时,加入completeTestBooking发邮件函数后就失败,大概率是超时导致Webhook发起方提前终止请求,或是发邮件环节存在未被记录的隐性异常,具体排查和解决步骤如下:
一、优先解决超时问题
绝大多数支付类Webhook服务都有严格的响应超时限制(通常3-5秒),而completeTestBooking里的SMTP邮件发送涉及外部网络请求,很容易因SMTP服务器响应慢、网络延迟等导致整个请求超时,Webhook发起方会直接返回400错误,但现有代码未捕获该场景。
解决方法:异步执行邮件发送
不要在请求流程内同步执行发邮件操作,改成后台异步执行,让complete.php快速返回响应给Webhook:
- 新建独立的邮件处理脚本
send_test_email.php:
<?php require 'PHPMailer/PHPMailer.php'; require 'PHPMailer/SMTP.php'; use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\SMTP; function completeTestBooking($testId) { $mail = new PHPMailer(true); try { // 原邮件配置逻辑 $mail->CharSet = "UTF-8"; $mail->SMTPDebug = SMTP::DEBUG_OFF; $mail->isSMTP(); $mail->Host = 'smtp.example.com'; $mail->Port = 465; $mail->SMTPAuth = true; $mail->SMTPSecure = 'ssl'; $mail->Username = 'info@co.uk'; $mail->Password = 'password'; $mail->setFrom('info@co.uk', 'Bookings'); $mail->addAddress('test@example.com'); $mail->isHTML(true); $mail->Subject = 'Here is the subject'; $mail->Body = 'This is the HTML message body <b>in bold!</b>'; $mail->AltBody = 'This is the body in plain text for non-HTML mail clients'; $mail->send(); file_put_contents('email_success.log', date('Y-m-d H:i:s') . " 邮件发送成功,测试ID: {$testId}\n", FILE_APPEND); return true; } catch (Exception $e) { file_put_contents('email_error.log', date('Y-m-d H:i:s') . " 测试ID: {$testId} | 错误信息: " . $e->getMessage() . "\n", FILE_APPEND); return false; } } // 接收命令行传入的测试ID $testId = $argv[1] ?? ''; if ($testId) { completeTestBooking($testId); }
- 修改
complete.php里的调用逻辑,用后台进程执行:
if ($jsonBookingDetails->type === "test") { // 后台执行邮件脚本,不阻塞当前请求 exec("php /绝对路径/send_test_email.php 1234 > /dev/null 2>&1 &"); savePayment($jsonBookingDetails->name, $address, $jsonBookingDetails->amount, $_GET['pid'], "Succeeded", $db); }
注意:必须使用脚本的绝对路径,避免系统找不到文件;
> /dev/null 2>&1 &用于让进程在后台静默运行,不干扰当前请求的响应。
二、补充日志排查隐性异常
现有代码中completeTestBooking的异常仅返回false,未记录任何信息,导致无法定位问题。给函数添加详细日志:
修改completeTestBooking的catch块:
catch (Exception $e) { // 记录错误时间、信息、栈追踪,便于排查 $logContent = date('Y-m-d H:i:s') . "\n错误信息: " . $e->getMessage() . "\n栈追踪: " . $e->getTraceAsString() . "\n\n"; file_put_contents('test_booking_error.log', $logContent, FILE_APPEND); return false; }
同时在complete.php里记录函数执行结果:
$emailResult = completeTestBooking("1234",$db); file_put_contents('complete_booking.log', date('Y-m-d H:i:s') . " 邮件发送结果: " . ($emailResult ? "成功" : "失败") . " | OID: {$_GET['oid']}\n", FILE_APPEND);
即使Webhook失败,也能通过日志明确邮件发送环节是否存在问题。
三、临时调整超时参数(可选)
如果暂时无法实现异步处理,可以给PHPMailer设置更短的超时时间,避免请求卡住:
// 在PHPMailer配置中添加 $mail->Timeout = 5; // 整体请求超时5秒 $mail->SMTPTimeout = 5; // SMTP连接超时5秒
同时给Webhook里的curl请求也设置超时:
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // curl请求总超时10秒 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // curl连接超时5秒
内容的提问来源于stack exchange,提问作者Abu Nooh
相关产品推荐
相关产品推荐

