HTTP 錯誤排查
HTTP 錯誤告訴你請求失敗,但通常不告訴你原因。從 403 就推斷「金鑰失效」只是一個披著數字的猜測。
源於真實事件(2026-07-30):一個第三方聯絡人資料豐富化 API 連續六天對每個呼叫返回 403 error code: 1010。這被解讀為「金鑰無權限」、「額度用盡」、「每月配額已達」。基於這個信念,建立了一個 756 行的瀏覽器自動化解決方案,並差點要求客戶檢查實際上正常的方案。真正原因是缺少 User-Agent,因此 CDN 在邊緣封鎖了客戶端。加上一個標頭就解決了:200 OK,完整資料,且信用額度一直都在。
在診斷前先執行這三個控制項
1. 無效憑證控制。 使用刻意偽造的憑證,以及完全沒有憑證,發送相同的請求。
for label, key in [("real", REAL_KEY), ("garbage", "0"*36), ("empty", "")]:
... # 相同URL、相同方法、相同標頭
如果三者返回相同的狀態碼和內容,則錯誤與你的憑證無關。它對權限、配額或有效性不提供任何資訊。停止推理關於金鑰的問題。
2. 無意義路徑控制。 請求一個肯定不存在的路徑,以及網站根目錄。
GET https://api.example.com/definitely-not-a-real-path-12345
GET https://api.example.com/
GET https://www.example.com/ # 他們的行銷網站
如果 API 錯誤也從行銷網站返回,則你被阻擋在原點之前。API 呼叫的相關內容無法幫助解決問題。
3. 讀取回應標頭,而不僅是內容。
except urllib.error.HTTPError as e:
print(e.code, e.headers.get("server"), e.read()[:200])
server: cloudflare 出現在「驗證」錯誤上就是一個明顯跡象。cf-ray、x-amzn-waf、akamai 也是。這些是基礎設施,不是 API。
已知特徵
| 症狀 | 真實原因 | 修正方法 |
|---|---|---|
403 + 內容 error code: 1010、server: cloudflare | Cloudflare 封鎖了客戶端簽名 | 發送真實瀏覽器的 User-Agent |
相同錯誤出現在所有路徑(包括 /) | 邊緣/WAF 封鎖或 IP 封鎖 | 更換 UA,然後更換 IP/代理 |
402 | 真正用完額度:請求已通過驗證 | 充值;金鑰沒問題 |
成功後立即出現 429 | 真正的速率限制 | 調整請求間隔,添加退避策略 |
帶有字段訊息的 400 | 你已到達 API 且驗證通過 | 修正酬載;這是好消息 |
400 驗證錯誤對於排查來說是成功信號:它證明驗證已被接受。
任何伺服器端 API 呼叫的預設標頭
Python 的 urllib 發送 User-Agent: Python-urllib/3.x,許多 WAF 會直接封鎖它。務必設定:
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36",
"Accept": "application/json",
"Content-Type": "application/json",
}
在進行大量呼叫前先量測成本
當 API 開始正常運作後,不要估算花費。在呼叫前後讀取使用量,並讀取提供者自己回應中的計費字段。
before = usage(); result = call(); after = usage()
print("charged:", result.get("billing"), "| measured:", before - after)
如何回報
說明你測試了什麼以及還有什麼未知。「兩個金鑰都返回 403」如果空白金鑰也返回相同的 403,就不是一個發現。應該這樣說:「這裡的 403 不具資訊價值,空憑證也會返回它;原因在驗證之前。」