支付寶雙通知機制(同步跳轉 return_url + 異步通知 notify_url)是保障訂單狀態最終一致性的核心設計。本文系統對比兩者特性、通知順序不確定性,並給出生產環境可用的處理邏輯與避坑指南。
| 維度 | return_url(同步跳轉) | notify_url(異步通知) |
|---|---|---|
| 觸發方式 | 用戶付款完成後,支付寶頁面自動跳轉 | 支付寶伺服器主動 POST 通知商戶伺服器 |
| 請求方法 | GET | POST |
| 參數獲取 | $_GET['out_trade_no'] | $_POST['out_trade_no'] |
| 可見性 | 用戶可見(瀏覽器地址列) | 用戶不可見(伺服器間交互) |
| 調試環境 | 本機可調試 | 必須在公網可訪問的伺服器 |
| 觸發次數 | 僅一次(用戶關閉頁面則不再觸發) | 多次重試(直到收到 success 或超過 24h22m) |
| 重試策略 | 無 | 8 次:2m, 10m, 10m, 1h, 2h, 6h, 15h... |
| 驗證有效期 | 1 分鐘 | notify_id 1 分鐘(驗證成功後失效) |
| 必須回應 | 無特定要求 | 必須輸出純文字 success(否則持續重試) |
| Session/Cookie | 可用 | 失效(無法獲取) |
| 頁面跳轉 | 允許 | 禁止(會導致支付寶判定失敗並重試) |
| 主要用途 | 用戶體驗:展示支付成功頁、引導下一步 | 業務保障:訂單狀態最終一致性、防止訂單丟失 |
關鍵原則:絕不可依賴通知到達順序判斷業務邏輯。
正確處理流程:
<?php
// 統一驗證入口(return_url 與 notify_url 共用)
function verifyAndProcess($params) {
// 1. 驗證簽名(支付寶 SDK 或自行實現)
if (!verifySign($params)) {
return ['success' => false, 'msg' => '簽名驗證失敗'];
}
// 2. 獲取核心業務標識
$outTradeNo = $params['out_trade_no'] ?? '';
$tradeStatus = $params['trade_status'] ?? ''; // TRADE_SUCCESS, TRADE_FINISHED 等
$tradeNo = $params['trade_no'] ?? ''; // 支付寶交易號
if (!$outTradeNo) {
return ['success' => false, 'msg' => '缺少商戶訂單號'];
}
// 3. 查詢本地訂單當前狀態
$order = getOrderByOutTradeNo($outTradeNo);
if (!$order) {
return ['success' => false, 'msg' => '本地訂單不存在'];
}
// 4. 幂等性檢查:已處理成功則直接返回
if (in_array($order['status'], ['PAID', 'COMPLETED'])) {
return ['success' => true, 'msg' => '訂單已處理', 'already_processed' => true];
}
// 5. 業務狀態機:僅允許合法狀態流轉
if (!in_array($tradeStatus, ['TRADE_SUCCESS', 'TRADE_FINISHED'])) {
return ['success' => false, 'msg' => '交易狀態非成功:' . $tradeStatus];
}
// 6. 執行核心業務(發貨、充值、開通會員等)
$result = processPaymentSuccess($order, $tradeNo, $params);
if (!$result) {
return ['success' => false, 'msg' => '業務處理失敗'];
}
// 7. 更新訂單狀態(資料庫事務)
updateOrderStatus($outTradeNo, 'PAID', ['trade_no' => $tradeNo, 'notify_time' => date('Y-m-d H:i:s')]);
return ['success' => true, 'msg' => '處理成功'];
}
// return_url 入口
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$result = verifyAndProcess($_GET);
// 顯示用戶友好頁面
showResultPage($result);
}
// notify_url 入口
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$result = verifyAndProcess($_POST);
// 必須輸出純文字 success
echo $result['success'] ? 'success' : 'fail';
exit;
}
?>
return_url.php?custom=1,需將自定義參數放入 out_trade_no 或 passback_params。success,任何其他內容(含 BOM、換行、錯誤堆疊)都會導致重試。out_trade_no + trade_no)並使用樂觀鎖/悲觀鎖。total_amount 與本地訂單金額,防止惡意篡改。notify_url 為 HTTPS、公網可訪問、無需登入即可存取遵循「同步通知負責體驗,異步通知負責兜底」的設計哲學,配合嚴格的幂等性與狀態機控制,即可構建穩健可靠的支付寶支付整合。