為什麼測試地址過不了 AVS 和 ZIP+城市+州 驗證
你為 QA 夾具產生了一個看起來很乾淨的美國地址 — 街道名合理、城市真實、郵遞區號
開頭數字也對得上、電話區碼也匹配。你把它貼到 staging 的結帳頁,結果表單拒絕它:
「您輸入的郵遞區號與城市/州不匹配。」更糟的是支付閘道回傳了 AVS_MISMATCH
,扣款失敗。
這兩種失敗其實都在正常工作。本文解釋背後的兩套系統 — USPS 驅動的「郵遞區號·城市· 州」驗證,與「地址驗證系統」(AVS) — 讓你能圍繞它們的規則設計測試資料,而不是和 它們對著幹。
兩層驗證,先簡短概覽
美國寄送表單通常會讓地址通過兩層獨立驗證:
- USPS 可投遞性驗證。確認城市、州、郵遞區號指向同一個 USPS 認可的郵 區,可選地確認街道號和街道名出現在真實的 USPS 投遞路線上。這就是「郵遞區號與城市 /州不匹配」這條錯誤的來源。
-
AVS — Address Verification System。卡組織(Visa、Mastercard、
Amex、Discover)的驗證:把帳單街道地址的數字部分和帳單郵遞區號與持卡人開戶行的
記錄做比對。這就是支付閘道回應裡
AVS_MISMATCH、AVS_ZIP_ONLY_MATCH等碼的來源。
注意這是兩套針對不同資料來源的不同驗證。一個合成地址可以通過第 1 層,但仍然 過不了第 2 層,因為銀行從來沒記錄過持卡人住在那裡。
USPS 郵遞區號比對怎麼運作
USPS 維護著一個資料庫,每個郵遞區號都關聯一個或多個「首選」城市名以及一個州。比如
裸郵遞區號 19801 唯一歸屬於德拉瓦州 Wilmington。如果你把
19801 配上 Dover, DE,驗證就會失敗,因為 Dover 的郵遞區號是
19901 和 19904 — 那是另一個郵區。
USPS 資料庫處理的幾個邊界情況,自己寫比對的常常踩坑:
-
可接受的備用城市名。
19711官方對應 Newark, DE,但 USPS 也接受 University of Delaware 作為投遞地址中的備用名。大多數第三方 驗證器會拒絕備用名,即便 USPS 實際上會投。 - 跨社區的郵遞區號邊界。一個郵遞區號可能橫跨多個城市名甚至多個 county。結帳表單常常接受任一被認可的名稱;CRM 有時會用「首選」名覆蓋使用者輸入。
- ZIP+4 精確度。4 位後綴把一個郵遞區號再細分到街區甚至單棟建築。 多數結帳表單接受但忽略它;一些物流 API 要求填它以拿到商業折扣價。
對測試夾具的現實結論是:城市、州、郵遞區號要從同一個州的記錄中取樣。 美國免稅州地址產生器就是這麼做的 — 如果它挑了德拉瓦, 城市就是德拉瓦的城市,郵遞區號也是那個城市真實的郵遞區號。第 1 層永遠過。
AVS 怎麼運作
AVS 工作在支付網路層。商戶向卡組織發起授權時,帳單地址裡的兩段會被發卡行與自己記錄 比對:
-
街道地址中的數字部分。
123 Main St和123 Maple Ave在 AVS 看來都是同一個 token123。 一些發卡行會忽略數字之後的所有字元。 - 5 位郵遞區號。
回應是一個字母碼,隨授權回傳。常見值:
| 碼 | 含義 |
|---|---|
Y | 街道和郵遞區號都匹配。 |
A | 街道匹配,郵遞區號不匹配。 |
Z | 5 位郵遞區號匹配,街道不匹配。 |
N | 都不匹配。 |
U | 發卡行未回應 / 資訊不可得。 |
G | 非美國發卡行,不支援 AVS。 |
Stripe、Adyen、Braintree、Authorize.Net 等支付閘道都會暴露這個碼,由商戶決定每個值
如何處理 — N 自動拒、A 或 Z 軟拒,依此
類推。
因為 AVS 比對的是銀行裡真實持卡人的記錄,任何合成地址都不可能通過真實的 AVS 驗證。隨機產生的街道和郵遞區號只可能在恰好真有持卡人住那的情況下匹配 — 而這恰恰是 AVS 要識別的情況。
針對每種環境設計能用的測試夾具
一個實戰指南:在不和驗證對著幹的情況下使用合成地址。
1. 單元測試和 UI 演示用「州一致」產生器
表單驗證、版面測試、截圖夾具、種子資料這些場景,你要的是看起來一致的地址,並不需要 通過任何外部 API。本站這樣的小型產生器提供的地址,城市、州、郵遞區號永遠內部匹配。
2. 在支付沙盒裡用官方測試卡 + AVS 測試郵遞區號
Stripe、Braintree、Adyen 都發佈了測試卡與「魔法地址」,在沙盒環境下能穩定
觸發指定的 AVS 回應。比如 Stripe 測試模式下,帳單郵遞區號 42424 一定
回傳 N(不匹配),其他任何 5 位郵遞區號都回傳 Y。AVS 相關
情境用這些有文件的魔法值,而不是泛用合成地址。
// Stripe 測試模式 —— 確定性 AVS 結果
const billing = {
line1: '1 Test Lane',
postal_code: '42424', // 強制回傳 AVS code N
};
const intent = await stripe.paymentIntents.create({ ... });
3. 單元測試裡 mock 掉地址驗證呼叫
如果程式碼會呼叫 USPS Address Information API、Smarty(前 SmartyStreets)、Lob、 Google Address Validation 之類,單元測試裡把這些 client stub 掉。合成地址不需要真的 通過 — 它們只是用來跑通你的程式碼路徑。要驗證的是你處理每種文件化回應(包括 partial-match 和 not-found)的程式碼是否正確。
4. 生產端到端測試用真實銀行地址
如果一定要在生產環境用真卡跑端到端測試,請用持卡人真實的帳單地址。繞不過銀行的記 錄。生產環境用合成地址做測試是出名的踩雷點 — 商戶帳戶可能被風控標記。
結帳還提示「郵遞區號不匹配」時怎麼排查
如果你的地址來自免稅州地址產生器但結帳仍報「不匹配」, 十有八九是下面三種之一:
- 結帳接了商用地址驗證 API(Smarty、Lob、USPS Web Tools),它們比郵遞區號 -城市-州走得更深,會要求街道號必須出現在 USPS 該郵遞區號的真實投遞清單 。合成街道號過不了。
- 結帳在「送出訂單」步驟跑 AVS,把 AVS 回應解碼成了表單錯誤。修法要麼沙盒裡關 AVS, 要麼把「預期失敗」寫進測試團隊的文件。
- 表單的郵遞區號資料過時,識別不了最近新增或重命名的郵遞區號。該升級資料集,而不是 改測試地址。
小結
兩層驗證、兩套資料來源、兩種失敗模式。USPS 郵遞區號-城市-州 驗證關心內部一致性 — 一個州一致的合成地址就能滿足。AVS 關心匹配銀行裡真實持卡人的真實 記錄 — 任何合成地址都過不了。按照這兩個原則去設計測試夾具,一大批莫名其 妙的測試失敗工單就不會再出現了。
資料來源與延伸閱讀
本文引用的 AVS 回應碼、USPS 資料庫欄位、支付閘道文件來自以下官方資料。AVS 碼語義因 閘道而異,請以你實際接的閘道為準:
- Stripe — 拒付碼與 AVS 結果 — 發卡行 AVS 回應的閘道側參考。
- Braintree — AVS 與 CVV 規則 — AVS 回應的可程式化規則。
- Authorize.Net — 回應碼參考 — 經典 AVS 字母碼表(Y, A, Z, N, U, R, S, E, G)。
- USPS Web Tools APIs — ZIP+4、地址標準化、city/state 查詢。
- USPS PostalPro — 可投遞性與 CASS 認證文件。
- Smarty — US Street Address API — 文中提到的商用 CASS 認證驗證 服務參考。