文件說一半,行為說實話
文件說一半,行為說實話
前言
最近串接一個電子簽核服務,要接「簽署完成」的通知。翻遍文件,關於這個通知欄位的說明只有一句話:
notifyUrl(字串、選填):簽署完成後,會發送通知到這個網址。
就這樣,沒了。POST 的內容是什麼?欄位有哪些?有沒有簽章驗證?打失敗會不會重送?文件通通沒寫。
接過外包案子或串第三方服務的人,這種狀況應該不陌生。廠商文件寫得潦草,能查的資料有限,問客服常常得到「應該是這樣,我再幫你確認」。
這篇就記錄一下這次怎麼把空白填起來,後面也聊聊系統後來怎麼設計,透過更好的做法進行串接工作。

文件沒說,不代表可以用猜的
一開始最想做的事情,其實是照著「業界常見做法」腦補:應該是 JSON 吧,應該會帶合約編號吧,應該……
腦補的問題在於,猜對了沒事,猜錯了就是上線後半夜被叫起來查 bug。
文件是廠商的「主張」,程式實際上會怎麼做,還是得靠實測驗證,猜測不能當依據。
所以換了個做法:先把不知道的事情列出來,再動手去問對方系統。
這種 webhook 類型的通知,通常搞不清楚的地方會落在幾件事:body 格式是 JSON 還是表單、欄位有哪些;
怎麼對應到我方資料,合約編號放在哪;什麼情況會觸發通知,只有簽署完成算,還是取消、失效也算;
有沒有驗證機制;打失敗會不會重送;期望我方回什麼。
先把這幾個問題寫下來,才知道等一下的實驗要驗什麼。
讓對方系統自己講清楚
想知道對方會送什麼,與其猜,不如架一個「什麼都收」的端點,讓真實請求打過來看個清楚。
兩種做法皆可看情境選:
優點:不用寫程式,五分鐘就能看到結果
缺點:資料會經過第三方,只能拿測試資料玩,真實合約與個資不能碰app.MapPost("/api/webhook/debug-capture", async (HttpRequest request, ILogger<Program> logger) =>
{
using var reader = new StreamReader(request.Body);
var body = await reader.ReadToEndAsync();
var headers = string.Join("\n", request.Headers.Select(h => $"{h.Key}: {h.Value}"));
logger.LogInformation(
"收到 webhook — Method: {Method}, Query: {Query}\nHeaders:\n{Headers}\nBody:\n{Body}",
request.Method, request.QueryString.Value, headers, body);
return Results.Ok();
});我自己是先用 webhook.site 探路,確認格式大概長怎樣之後,再切到本機端點做完整測試,
畢竟後面要驗證重試、驗證多筆通知的情境,留在自己的開發環境比較方便。
實驗的時候要記得一次只改一個變因。想知道「取消會不會通知」,就只觸發取消,不要同時又換了別的設定,
不然觀察到的結果會分不清是哪個動作造成的。
測完,把結果寫下來
實驗做完不能只放在腦子裡。我自己是開一份文件放進專案的 docs,記幾件事:測試日期與對方系統版本,因為沒寫進文件的行為,
人家哪天改版說變就變;每個問題實測到的答案,附一段原始 request 當證據;測不出來的項目,老實標成「未知」,不要憑印象亂填。
這份記錄後來真的派上用場,拿著實測結果去問廠商窗口:「我們觀察到重送間隔大概是五分鐘,這是保證行為嗎?」,
對方書面回覆之後,才算真正從「觀察」升級成「規格」。沒回覆的部分,就繼續當作未知的風險看待。
把通知當門鈴,不要當包裹
實驗歸實驗,這些觀察到的行為終究只代表對方系統「現在」怎麼做,不保證以後也一樣。真的要上線,實作不能靠這些沒寫進文件的細節撐著。
後來我們的處理方式是:收到通知,只從裡面挖出一個東西,就是合約編號,其他內容一律不信。挖到編號之後,回頭主動打文件有保證的查詢 API,拿查詢結果當作唯一真相,再拿這個結果去更新自己系統的狀態。
對方系統 ──POST(格式不保證)──▶ 我方 webhook 端點
只挖出合約編號
│
▼
我方 ──GET 查詢合約狀態(文件保證的 API)──▶ 對方系統
│
▼
依查詢結果更新狀態說白了,通知只是拿來叫醒我們去查最新狀態的門鈴,不是包裹本身。包裹裡裝什麼,還是得靠查詢 API 這個有保證的管道去確認。
先說清楚,「門鈴」只是這次踩雷後自己取的白話說法,不是正式的設計模式,跟 Observer Pattern 那種訂閱/推播機制是兩回事。webhook 本身怎麼推播是一件事,收到推播後信不信裡面的內容,是另一件事,這裡講的是後者。
這樣做的好處很實際:對方哪天改了 POST 的格式,只要合約編號還挖得到,我方完全不受影響。而且 webhook 端點目前也沒有簽章驗證,理論上誰都能打過來,但因為狀態最終都是靠查詢 API 決定,偽造的通知頂多讓我們多查一次,不會真的把假資料寫進系統。
順手記幾個習慣
除了門鈴模式,這次踩雷後另外養成幾個習慣,之後接文件不完整的 API 應該都用得到。
原始的 request body 先整包存起來再解析,之後對方改格式或有爭議,第一手證據還在。
解析對方丟過來的資料時儘量寬鬆,容忍多餘欄位或大小寫不一致;反過來,我方送出去的資料就照文件老實寫,該怎麼填就怎麼填。
處理通知的邏輯也做成可以重複執行不出錯,因為不知道對方的重試策略,
乾脆假設同一筆通知可能收到好幾次,狀態更新用「查完覆寫」而不是「累加」,重送幾次都不怕。
還有一點,實驗中看到某個沒寫進文件卻很好用的欄位,也不要因此就依賴它。用歸用,能不能長期依靠是另一回事,
文件沒保證的東西,對方隨時可以說改就改。
小結
- 文件不完整時不要用猜的,先把不知道的事情列成清單,再動手驗證。
- 用 webhook.site 或本機端點加通道工具,讓對方系統自己把請求打過來給你看。
- 實驗一次只動一個變因,結果連同日期、對方版本一起記錄下來,拿去跟廠商書面確認。
- 實作上採「門鈴模式」:通知只當觸發器,狀態一律以主動查詢的結果為準。
- 養成原始資料落地、寬進嚴出、處理邏輯冪等的習慣,未文件化的行為看看就好,別真的靠它。
職場走跳誠心建議:跟廠商要書面確認,不只是為了拿到正確規格,也是職場自保之道。