加班有據開發筆記(三):第一筆真錢進來之前,我踩到的那些洞
引擎對了、資料進得來,接下來是最現實的一段:收錢。勞工端是單次付費解鎖完整計算書,雇主端是月訂閱。這篇記錄我接綠界金流、一路到正式站真的入帳的過程——踩的洞比寫引擎還多。
1. 第一件事不是寫程式,是查哪家能用
我原本想用 Stripe,查了才知道台灣不是 Stripe 的商家支援國;PayPal 的境內交易也關了。剩下的是本土金流:綠界、藍新。我選綠界,理由很務實——個人賣家能申請、信用卡與 ATM 都支援、文件與測試環境齊全。
另一個提早發現的相依:送審需要一個販售網址。所以部署順序變成先上線、再送審,不是做完再一起上。
2. CheckMacValue 用官方測試向量當 golden tests
綠界每一筆往返都要帶一個驗證碼,由參數排序、串接、URL 編碼、雜湊算出來。聽起來簡單,但細節很多:空格、加號、單引號、波浪號,還有 .NET 風格的編碼例外字元。
我沒有自己想測資,直接拿綠界官方公開的測試向量當 golden tests,全數通過才往下接。這跟第一篇寫引擎的做法一樣:先有已知答案,再寫程式去對。
3. 付款成功了,畫面卻回到第一步
正式站第一次試付,錢扣了、綠界後台顯示成功,回到我的網站卻停在步驟一,沒解鎖。查了半天,根因是我自己的安全檢查:我要求所有 API 請求都帶 Origin 標頭,但瀏覽器對同源的 GET 根本不會帶——於是使用者回站查訂單時,被自家的 403 擋掉。
webhook 其實全程正常,訂單在資料庫裡早就是已付款。修法是「Origin 存在且跨站才擋」,並補上迴歸測試。這個 bug 讓我學到:安全檢查本身也要有測試,不然它擋到的第一個人可能是付了錢的客戶。
4. 瀏覽器回站與 webhook 是兩條路,誰先到不一定
綠界把使用者的瀏覽器導回我的網站,跟把付款結果送到我的伺服器,是兩條獨立的路。使用者可能比 webhook 先到,畫面就會短暫停在「尚未完成付款」,得自己重新整理。
我補了前端輪詢:前密後疏,約兩分鐘後放棄,而且有明確的終止條件——已付款就停、等 ATM 時拿到虛擬帳號就停、綠界已回失敗原因也停。等滿之後的訊息要講清楚「已扣款請勿重複付款」。另外,webhook 的每一個失敗分支都要留 log:錢可能已經扣了,沒記就永遠不知道那一筆發生了什麼。
5. 訂單編號要親手交到使用者手上
我查過,綠界並不保證一定會寄通知信給消費者。所以訂單編號這件事不能靠別人:解鎖畫面常駐並一鍵複製、印進計算書頁首、ATM 資訊卡上也有、入帳後自己寄一封付款完成信。而且只在 webhook 這條伺服器路徑寄,不在瀏覽器回站時寄——不然會寄兩封。
正式站第一筆真實付款走完那天,時間軸是:建單、webhook 入帳、付款完成信收到、回站自動解鎖。全部通了。下一篇寫上線之後——我以為引擎已經很穩,結果重新審視一次,找出八個問題。