錢包不再刷新,應用卡在轉圈,背後某處提示速率限制已超出。你的私鑰、餘額和鏈本身都沒有問題。是某個營運方判定你在給定視窗內提出的問題超過了方案允許的數量,於是把越過那條線的請求擋了回去。
速率限制報錯到底在報甚麼
RPC 節點是一台替那些不自己跑節點的錢包和應用回答鏈上問題的機器。營運這台機器的人同時也決定每個呼叫方能問多少個問題,並透過拒絕天花板之上的一切來落實這個決定。
RFC 6585 給這種拒絕定了一個專門的狀態碼。它寫明 429 狀態碼表示用戶在給定時間內發送了過多請求,該節把這種情形稱作速率限制;並補充說回應體 SHOULD 包含說明該情形的細節,MAY 包含一個 Retry-After 標頭,指出在發起新請求前應等待多久。
由此有兩個後果,盯著壞掉的畫面時都容易忽略。這次拒絕針對的是呼叫方而不是這一次呼叫,所以同一個請求早一刻發出本來會成功。而這個天花板是某一個營運方的策略,不是網絡的屬性,所以另一個策略不同的端點可以毫無怨言地回答同樣的請求。
這次拒絕會裝在不止一種信封裡
不是每一次被限流的呼叫都以 HTTP 狀態碼的形式回來。JSON-RPC 2.0 把錯誤裝在回應體裡,其規範把 -32000 到 -32099 這段代碼保留給實作自訂的伺服端錯誤,服務商的限流提示就可能落在這裡。此時 HTTP 層報的是一次普通的成功。
| 拒絕落在哪一層 | 它長甚麼樣 | 為甚麼會被漏掉 |
|---|---|---|
| HTTP 狀態碼 | 一個 429 回應,有時帶 Retry-After 標頭 | 只檢查連線是否成功的客戶端看不見 |
| JSON-RPC 回應體 | 一個帶實作自訂伺服端錯誤碼的 error 物件 | HTTP 狀態是成功,狀態檢查會把它放過去 |
| 客戶端措辭 | 陳舊的餘額、一個轉圈圖示,或者一句泛泛的網絡失敗 | 措辭是寫給人看的,不會點名是哪一層拒絕了 |
所以診斷先要判斷你看到的是這三者中的哪一種。錢包只說連不上,不等於沒有發生拒絕,只等於錢包沒有把拒絕呈現出來。
限額不總是按請求數計的
按每秒呼叫數表述的天花板只是限額的一種形狀。當營運方給呼叫加權而不是數個數時,一個重方法從同一份預算裡取走的比一個輕方法多,預算清空的速度會快於呼叫數給人的感覺。
所以只發了幾個呼叫和你超限了,可以同時是對同一分鐘的準確描述。一條跨越很寬區塊範圍的日誌查詢,按個數算是一次呼叫,按權重算是一筆大額支取。讀營運方自己關於預算按甚麼計的說明,比拿它做實驗要快。
請求量究竟從哪裡來
請求量是累積出來的,不是選出來的。它來自那些沒人當成迴圈的迴圈:一個按計時器重讀餘額的介面、一個每次重新渲染都重新取數的元件、一個反覆追問交易落沒落的背景監視器。
因為間隔很小而工作階段很長,這筆帳算起來毫不留情。一個每秒刷新一次餘額的介面,在十二小時的工作階段裡光靠自己就產生 43,200 次呼叫,還沒算任何用戶操作。對著一份每天允許 100,000 次呼叫的方案,一個開著的分頁已經吃掉了一天裡相當大的一塊。
重試是第二個來源,而且它會把第一個來源放大。一個用再發一次來回應每次拒絕的客戶端,會把一次超限變成一串超限,而且恰好發生在營運方最不願意服務它的時刻。
重試時不要把拒絕弄得更糟
按造成拒絕的那個間隔再發一次,只會複現那次拒絕。正確的糾正是每失敗一次就等得更久一些,而不是每次等一樣久,讓間隔增長而天花板留在原地;並且在有限次嘗試之後停下,而不是無限地繼續。
給這個等待加上隨機量。在同一瞬間被拒絕、又按同一條規則退避的客戶端,會在同一瞬間一起回來,於是恢復本身又成了一次衝擊。用一個隨機偏移把等待攤開就能打破這種同步,而且不花甚麼代價。
當回應裡帶著 Retry-After 標頭時,它取代了猜測。營運方已經說明要等多久,遵守這個值既比你自己發明的時間表更快,也更不容易被記在你頭上。
與其抬高天花板,不如削減請求數
批次是第一項削減,而且它屬於協定本身,不屬於任何一家服務商。JSON-RPC 2.0 寫明:為了同時發送多個 Request 物件,客戶端 MAY 發送一個裝滿 Request 物件的陣列;伺服端應當在處理完批次中的全部 Request 物件之後,以一個裝著對應 Response 物件的陣列作答。把十個呼叫摺進一個陣列,就把上面那個 43,200 次呼叫的工作階段變成 4,320 次請求。
快取是第二項。在兩個區塊之間不會變的值,不需要在兩個區塊之間反覆重讀:一個代幣的精度、一個合約地址、一筆已經結清的交易的收據。凡是終局的東西都可以無限期快取,重讀它純屬白花。
訂閱是第三項,前提是端點提供。輪詢一遍遍地問某個東西變了沒有;訂閱只問一次,然後在答案改變時被告知。兩者攜帶的資訊相同,消耗的預算卻差得很遠。
| 你觀察到甚麼 | 天花板其實在哪 | 甚麼能改變它 |
|---|---|---|
| 用量不大卻被拒 | 加權預算被重方法花掉了 | 收窄區塊範圍,把查詢拆開 |
| 第一次之後拒絕成倍增加 | 重試正把請求撞向天花板 | 用增長且帶隨機量的等待退避 |
| 一個閒置分頁就觸發拒絕 | 一個按計時器跑的輪詢迴圈 | 用批次、快取或訂閱取代輪詢 |
| 只有某一條網絡被拒 | 掛在那個端點上的策略 | 為那條網絡再加一個端點 |
甚麼時候重試不是安全動作
讀和寫的可重複性並不相同。多問一次餘額,代價只是多一次呼叫。把一筆已簽名的交易發第二次則是另一回事,而端點處的拒絕並不告訴你這筆交易停在這條界線的哪一邊。
在重發之前,先弄清第一次嘗試有沒有進到內存池。網絡已經持有的一筆交易,和一筆表達同樣意圖的新交易,並不能互換,把兩者當成一件事正是重複廣播的來路。在 Solana 上,新鮮度參照讓時間關係變得直白:被長退避拖住的提交可能撞上過期 Blockhash,需要重建而不是重發。
同樣的謹慎也適用於此後客戶端相信的東西。一個讀請求正在被拒絕的錢包,是拿自己記的已發交易數去比對一份它刷新不了的視圖,這正是走到 Nonce 太高提示的路徑之一。計數沒有錯,錯在被拿來比對的那幅畫面是缺的。
換端點只修好一種成因,修不了其餘的
如果天花板屬於營運方,換到另一個營運方就是換到另一個天花板之下,切換端點正是這種情況下的常規修復。在把任何東西路由過去之前先核對新條目的鏈 ID,並保留本來能用的那一條。換端點夠不到的是鏈上已經記下的東西:一筆跑過又被回滾的交易是已回退狀態,任何誠實的端點報出來的那張收據都一模一樣。
如果請求量屬於你自己,這一換只是買到時間,別的甚麼也沒買到。同一個輪詢迴圈會按同樣的時間表撞上下一個營運方的天花板;在多個端點之間輪換以同時待在幾個天花板之下,是把迴圈藏起來而不是修好它。
還有第三種情況值得與前兩者分開。一個綁定你自己密鑰的專用端點不只是更大的額度,它還把你與共用一個公共端點的其他呼叫方隔開,因此此後你收到的拒絕確實是你自己要解釋的。
小結
速率限制報錯說的是你要了多少,而不是你有沒有資格要。它點出的是一份預算、一個視窗和一個營運方,有用的回應從判斷這三者裡哪一個正在起約束作用開始。
在拒絕落下的那一層去讀它,營運方給了 Retry-After 就照辦,用增長且帶隨機量的等待退避,而不是按老時間表再發一遍。然後去削減請求量,而不是追求更大的天花板:能一起走的就批次走,不會變的就快取,能訂閱就不要輪詢。額度翻一倍,被同一個迴圈消耗,還是在同一個下午耗盡。想繼續打好這些基礎,請追蹤 Bitbase(幣貝)學院的更多內容。
相關閱讀
幣貝上與本主題相關的其他文章:
風險披露:本文為 Bitbase(幣貝)學院的科普內容,僅供教育與資訊參考,不構成任何投資、交易、稅務或財務建議。加密資產波動劇烈,請自行評估風險。本文撰寫於 2026 年 9 月,請以官方最新資訊為準。
參考資料
[1] M. Nottingham、R. Fielding,Additional HTTP Status Codes,RFC 6585,IETF,2012 年 4 月 rfc-editor.org
[2] JSON-RPC 2.0 Specification,JSON-RPC 工作組,2013 年 1 月 4 日更新 jsonrpc.org






