WooCommerce结账订单重复及会话异常问题排查求助
约一周前,代码库未做任何更改,但开始频繁收到重复订单——每10笔订单中就有1笔重复。插件和WordPress均未开启自动更新,且只有我有权限操作此类更新。用户反馈的报错主要有两种:
- "Sorry, your session has expired."
- "Please check the reCaptcha box to place your order."
用户不知道订单已创建,会再次点击下单按钮以尽快收到商品。
部分用户无任何报错信息:调用/?wc-ajax=checkout的AJAX请求已完成,但未跳转到订单确认页。这一点很关键——无论请求成功或失败,订单都会创建,但用户并不知情;请求成功时浏览器也不会跳转。
为排查问题,临时修改了wp-includes/functions.php中的wp_send_json函数添加日志,发现JSON响应无异常,但部分成功响应未触发跳转:
{ "result": "success", "redirect": "https://example.com/checkout/order-received/123456/?key=wc_order_ABCabc123xyz", "order_id": 123456 }
这看起来是JavaScript错误:调用wc_checkout_params.checkout_url的AJAX请求的success方法本应触发跳转,但实际未执行。尝试禁用结账页的多个插件及第三方JavaScript资源,甚至关闭Varnish,均无效果。联系Cloudways服务商,对方表示未对服务器做任何更改。
下一步验证服务器的JSON响应是否被checkout.js接收,于是修改checkout.min.js,添加函数将第一次请求的响应通过二次AJAX发送至服务器记录:
function logServerResponse(res,ts,xhr,err){ var h = xhr && xhr.getAllResponseHeaders ? xhr.getAllResponseHeaders() : "N/A"; var payload={ result: res ? JSON.stringify(res) : "N/A", textStatus: ts, headers: h, error: err || "" }; e.ajax({ url:"/abc.php", method:"POST", cache:false, data:payload, dataType:"json" }) };
在第一次AJAX请求的success和error方法中添加该函数调用,并更新方法参数以传递所需数据:
修改后的Success方法
success:function(c,wy,wz){ logServerResponse(c,wy,wz,""); //... }
修改后的Error方法
error:function(e,o,c){ logServerResponse(null,o,e,c); //... }
此时发现部分服务器响应未被记录:/abc.php的日志脚本本应每次都记录,但实际并未做到:
<?php $d = new DateTime('now', new DateTimeZone('America/Chicago') ); // Define the log file path $logFile = __DIR__ . '/' . $d->format('Y-m-d') . '.log'; // Check if required keys exist in $_POST if( ! isset( $_POST['result'] ) OR ! isset( $_POST['textStatus'] ) OR ! isset( $_POST['headers'] ) OR ! isset( $_POST['error'] ) ){ // Silently fail if all post vars not present http_response_code(200); exit; } // Prepare the log entry $logEntry = [ 'timestamp' => $d->format('Y-m-d H:i:s'), 'post_data' => [ 'result' => $_POST['result'], 'textStatus' => $_POST['textStatus'], 'headers' => $_POST['headers'], 'error' => $_POST['error'], ] ]; // JSON-encode with pretty printing $jsonData = json_encode( $logEntry, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); if( $jsonData === FALSE ) { $jsonData = json_encode([ 'timestamp' => $d->format('Y-m-d H:i:s'), 'message' => 'Posted data could not be encoded successfully', ]); } // Ensure the log entry ends with a newline, and add an extra empty line $logContent = $jsonData . "\n\n"; // Append to the log file if( file_put_contents( $logFile, $logContent, FILE_APPEND | LOCK_EX ) === FALSE ) { error_log("Failed to write to $logFile in abc.php"); } if( ! is_file( $logFile ) OR ! is_writable( $logFile ) ) { error_log("$logFile is not writable in abc.php"); } // Send a simple response (optional, for AJAX confirmation) header('Content-Type: application/json'); echo json_encode([ 'status' => 'logged' ]); ob_flush(); flush();
更复杂的是,问题根源似乎与WooCommerce会话相关:用户反馈的报错、ReCaptcha错误通过woocommerce_checkout_process动作及wc_add_notice无法阻止class-wc-checkout.php的process_checkout方法创建订单;完全禁用ReCaptcha后,用户更可能看到"Sorry, your session has expired."报错。
另外,开发环境中可无限下单而无此问题。生产环境部署在Cloudways托管的Linode服务器,开发环境为Ubuntu服务器,LAMP栈与Cloudways基本一致,Cloudways当前栈为Varnish + Nginx + Apache。
该问题为间歇性,仅影响约10%的订单。求问:为何无代码更改的情况下突然出现?为何不影响所有订单?下一步排查方案是什么?
内容的提问来源于stack exchange,提问作者Brian Gottier

