跳轉到主要內容

return_url 和 notify_url 有什麼區別?為什麼不能用支付回跳判斷支付成功

買家付款後跳回你的頁面,不代表錢已經到賬。本文對比同步回跳 return_url 與異步通知 notify_url,列出回跳缺失、提前或被偽造的真實場景,並給出判斷支付成功的正確做法。

發佈於 約 4 分鐘閲讀

手繪插畫:瀏覽器地址欄顯示 return?paid=1,頁面中間是一個問號,旁邊一個人懷疑地看着
本文目錄
  1. return_url 與 notify_url 的區別
  2. 為什麼瀏覽器回跳不可靠?
  3. 判斷支付成功的正確做法
  4. 如果通知遲遲沒來
  5. 兩個容易忽略的細節
  6. 總結

return_url 是給買家看的:付款結束後,把買家的瀏覽器帶回你的網站。notify_url(或 Webhook)是給你的服務器的:支付平台確認結果後,從服務端直接通知你。

判斷一筆訂單是否支付成功,只能依據驗簽通過的異步通知,或者你的服務端主動查詢訂單的結果,不能依據瀏覽器回跳。 這條規則在幾乎所有支付平台都成立,下面解釋為什麼。

return_url 與 notify_url 的區別

return_url(同步回跳)notify_url / Webhook(異步通知)
誰發起買家的瀏覽器支付平台的服務器
什麼時候發生買家在收銀台操作結束、瀏覽器跳回時平台確認支付結果之後
一定會發生嗎不一定:買家可能關掉頁面會,失敗還會按計劃重試
能被偽造嗎能:任何人都可以手動打開這個地址不能:請求帶簽名,沒有密鑰無法偽造
用來做什麼展示結果頁、引導下一步改訂單狀態、發貨、開通服務

為什麼瀏覽器回跳不可靠?

買家付了錢,卻沒有回來

用錢包付款時,買家常常是在另一個應用裏完成授權的。授權成功後他可能直接關掉了瀏覽器,或者手機切到了別的應用,你的 return_url 永遠不會被訪問。如果你的系統只在回跳時更新訂單,這筆錢就成了「收了款卻沒發貨」。

回來了,但錢還沒有確定

需要 3D Secure 驗證的銀行卡、需要掃碼或跳轉授權的錢包,都有一段「買家已經操作、結果尚未最終確定」的時間。買家回到你的頁面時,這筆支付可能仍在處理中,甚至最終失敗。

回跳地址可以被手動打開

return_url 只是一個普通網址。如果你的回跳頁面看到 ?paid=1 之類的參數就認為支付成功,任何人複製這個地址在瀏覽器裏打開,都能「支付成功」。

同一筆訂單可能經歷多次支付嘗試

買家在收銀台先選了一種方式、沒完成,又換了另一種,一張訂單在付款過程中可能先後對應多筆渠道支付。以「某一次回跳」為準,很容易和最終真正成功的那一筆對不上。

判斷支付成功的正確做法

下單時帶上 notify_url,或配置 Webhook 端點

正式環境裏,訂單必須有地方接收結果通知:要麼每筆訂單傳公網 HTTPS 的 notify_url,要麼在控制台配置訂閲了 payment.succeeded 的 Webhook 端點,否則下單會被拒絕。見 統一下單。

把買家重定向到收銀台

使用接口返回的 checkout_url。

回跳頁面只展示狀態,不改訂單

買家回到 return_url 時,頁面向你自己的後端詢問訂單狀態:已支付就展示成功;還在處理中就展示「正在確認支付結果」並稍後刷新。後端讀的是你自己的訂單表,必要時調用 訂單查詢 向平台核實。

收到驗簽通過的通知後再履約

驗簽、按事件 id 去重、在同一個事務裏更新訂單並開通服務,然後返回 2xx。細節見 支付回調重複通知怎麼辦。

回跳頁面的後端查詢大致是這樣:

curl "https://api.kukopay.com/v1/orders/TRD_9F3A2C7E..." \
  -H "X-Api-Key: $KUKOPAY_API_KEY"

返回的 status 為 paid 時才表示支付成功並已入賬;pending 表示仍在等待。

不要讓前端直接帶着 API Key 去查訂單。密鑰只能放在服務端,前端只問你自己的後端。

如果通知遲遲沒來

通知延遲或者全部失敗時,你還有兩條補救路徑:

  • 主動查單。 訂單在你那邊一直是待支付,但買家説已經付了款?用訂單查詢接口問一次平台。
  • 從事件接口補回。 KukoPay 的每一個支付結果都會先記錄成事件,推送只是一次送達嘗試。接收端宕機期間錯過的事件,可以用 事件接口 按時間範圍拉回來。

平台這一側也有兜底:後台對賬任務會持續核對未決的支付和退款,即使渠道的通知丟了、買家又關了頁面,平台也會重新讀取渠道結果,補入賬、補通知或關閉訂單。

兩個容易忽略的細節

訂單關閉後才到達的付款會被自動退回。 極少數情況下,買家的付款在訂單已經被另一筆付款支付、或已經超時關閉之後才到達。KukoPay 會把這筆錢全額原路退回買家,發送 payment.duplicate_refunded 通知,不影響商戶餘額,也不需要你處理。

對賬請用訂單號,不要用 payment_id。 因為一張訂單可能先後對應多筆渠道支付,訂單對象上的 payment_id 會變化。請以 trade_no / out_trade_no 和 payment.succeeded 事件對賬。

總結

  • return_url 負責體驗,notify_url / Webhook 負責結果;
  • 回跳可能不發生、可能太早、可能被偽造;
  • 履約只看驗簽後的通知或服務端查單;
  • 回跳頁面只讀狀態、不改狀態。

想親手驗證這些場景,可以在沙箱裏用需要 3D Secure 的測試卡 4000 0000 0000 3220,或者選擇錢包支付後在測試授權頁直接關掉瀏覽器,看看訂單是否仍然入賬、通知是否照常到達。測試卡列表見 沙箱測試。

在沙箱裏把它跑通

註冊商戶後即可申請測試密鑰,不需要等待資質審核。