WebSocket 訂閱
用 WebSocket 訂閱即時區塊頭與日誌:連線後用 eth_subscribe 訂閱新區塊頭,日誌篩選器需指定地址或主題,否則傳回 -32602;單把 key 的連線數有上限,斷線後按退避重新連線並補掃缺失區塊。
BlockVectra 提供安全的 WebSocket 連線(wss://),可在標準 JSON-RPC 請求之外串流即時以太坊事件訂閱。
選擇 WebSocket、Webhook 或輪詢
當你的應用程式能維持連線時,請使用 WebSocket 接收即時 newHeads 與篩選後的 logs。若要在 HTTPS 端點接收關注錢包的活動,請使用區塊鏈 Webhook API,並具備原始主體簽章驗證、重試與保留相符事件的重放。若要用於排程的 ERC-20 收款監控與歷史日誌回填,請使用 HTTP 輪詢。穩定幣指南也示範了 USDT / USDC Webhook 接收端。若要從鏈支援、接收端需求與復原取捨等架構面比較各種方式(供開發者與 AI Agent 參考),請參閱選擇 Webhook、WebSocket 或 RPC 輪詢指南。
WebSocket 支援來自 GET /v1/chains 中的 ws 與 subscriptions;Push 支援來自需認證的 GET /v1/push/chains 清單。沒有 WebSocket 的鏈,只要列於該清單,仍可使用地址 Webhook。
WebSocket 斷線後需要重新訂閱與回填;它不會發出 Push 控制事件 subscription.gap 或 chain.reorg。就 Webhook 而言,缺口需要範圍掃描;重組通知則需要先標記或捨棄被取代的事件,再保留自動重新遞送的規範事件。Push 重放會重新遞送保留的相符事件,而非地址或鏈加入之前,或訂閱離線期間的資料。實作復原時,請參閱計費規則與錯誤參考。
可用的鏈
你可以讀取 GET /v1/chains 中的 ws(布林值)與 subscriptions(支援型別的陣列),確認某個網路是否啟用 WebSocket 訂閱。
下表列出已啟用 WebSocket 支援的網路:
| 鏈 | WebSocket 端點(路徑攜帶 Key) |
|---|---|
| Robinhood Chain | wss://api.blockvectra.com/v1/robinhood_mainnet/{api_key} |
| Robinhood Chain Testnet | wss://api.blockvectra.com/v1/robinhood_testnet/{api_key} |
連線與認證
用戶端建立安全的 TLS WebSocket 連線(wss://)。API key 可以兩種方式提供:
- 路徑 key:
wss://api.blockvectra.com/v1/{chain}/{api_key} - 標頭 key:
wss://api.blockvectra.com/v1/{chain},在 HTTP Upgrade 握手期間帶上x-api-key: {api_key}或Authorization: Bearer {api_key}標頭。
使用路徑 key 時,會採用路徑 key,並忽略兩個認證標頭。沒有路徑 key 時,非空的 x-api-key 優先於 Authorization: Bearer。瀏覽器 WebSocket API 無法設定這些標頭;請使用路徑 key URL。
握手准入檢查
握手可能以下列原因失敗:
- 認證:缺少 API key 會回傳 HTTP 401(
missing_api_key);未知、已停用或已撤銷的 API key 會回傳 HTTP 401(invalid_api_key);若認證暫時無法使用,回應為 HTTP 503(auth_unavailable)。 - 帳戶餘額:預付餘額為零或負數的帳戶會回傳 HTTP 402(
balance_exhausted);若無法確認計費狀態,回應為 HTTP 503(billing_unavailable)。 - 連線限制:超過單 key 限制(20 條連線)或單帳戶限制(50 條連線)會回傳 HTTP 429(
ws_connection_limit)。 - 鏈可用性:請求未知或未提供服務的鏈會回傳 HTTP 404(
unknown_chain)。 - 伺服器容量:當伺服器忙碌或過載時,握手會回傳 HTTP 503(
overloaded)並附帶Retry-After標頭。
連線後,用戶端可以傳送標準 JSON-RPC 2.0 請求(例如 eth_blockNumber 或 eth_call),以及以 UTF-8 文字訊框格式化的訂閱控制方法。
計費規則
- 建立連線、保持閒置連線開啟,以及 ping/pong 心跳不計費。
- 成功的
eth_subscribe與eth_unsubscribe呼叫會計費,包括回傳false的退訂;失敗的呼叫不計費。一般 JSON-RPC 呼叫依 JSON-RPC 計費規則處理。 newHeads通知以每條連線、每個區塊雜湊計一次,與該連線擁有多少個newHeads訂閱無關。logs通知以每個訂閱、每個有相符日誌的區塊雜湊與階段計一次;沒有相符項的區塊不計費。同一區塊與階段中的多筆相符日誌不會增加費用。不同訂閱分別計費,即使其篩選條件重疊。重組日誌(removed: true)另計一個單位;同一高度的替代區塊具有不同雜湊,屬於不同單位。- 通知僅在成功寫入 socket 傳送緩衝區後才計費;已排入佇列或遭丟棄且未寫出的通知不計費。在
eth_unsubscribe應答前已排入佇列的通知,若成功寫出仍會計費。WebSocket 訊息不攜帶 HTTP 計費標頭;請查詢帳戶用量以取得已計量的 CU。
訂閱方法
此 API 實作標準的以太坊發布/訂閱介面:eth_subscribe 與 eth_unsubscribe。
newHeads
每當新區塊附加到鏈頭時,發出新的區塊頭物件。
- 訂閱請求:
{"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["newHeads"]} - 訂閱回應:回傳不透明的十六進位訂閱識別碼:
{"jsonrpc":"2.0","id":1,"result":"0x1"} - 推送通知訊框:
{"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x1","result":{"number":"0x1b4","hash":"0x..."}}}
logs
發出符合指定篩選條件的日誌事件。
-
篩選條件要求:每個
logs訂閱篩選器必須指定address(合約地址或地址陣列)或topic0(第一個主題位置,非 null)。兩者皆未指定的篩選器(例如{}或{"topics":[null,"0x..."]})會以錯誤碼-32602(logs_filter_required)拒絕。 -
篩選限制:最多 100 個地址;最多 4 個主題位置,且每個位置最多 16 個候選雜湊。
-
篩選容量:若作用中的日誌篩選器達到容量上限,訂閱會回傳錯誤碼
-32022(ws_filter_capacity)。 -
鏈重組:若某個區塊因鏈重組而被移除,被移除日誌的通知會帶有
"removed": true。 -
訂閱請求:
{"jsonrpc":"2.0","id":2,"method":"eth_subscribe","params":["logs",{"address":"0x1234567890123456789012345678901234567890"}]}
eth_unsubscribe
使用訂閱識別碼終止作用中的訂閱。
- 退訂請求:
{"jsonrpc":"2.0","id":3,"method":"eth_unsubscribe","params":["0x1"]} - 退訂回應:
{"jsonrpc":"2.0","id":3,"result":true}
可執行範例
使用 viem v2,透過 createPublicClient 與 webSocket 傳輸層連線。請將 {chain} 替換為目標鏈識別碼,並將 {api_key} 替換為你的 API key:
import { createPublicClient, webSocket } from 'viem';
const apiKey = process.env.BLOCKVECTRA_API_KEY || '{api_key}';
const url = `wss://api.blockvectra.com/v1/robinhood_mainnet/${apiKey}`;
const client = createPublicClient({
transport: webSocket(url),
});
// 1. 訂閱新的區塊頭(newHeads)
const unwatchBlocks = client.watchBlocks({
onBlock: (block) => {
console.log('New block header received:', block.number, block.hash);
},
onError: (error) => {
console.error('watchBlocks error:', error);
},
});
// 2. 訂閱合約事件日誌(篩選條件需要 address 或 topic0)
const unwatchEvents = client.watchEvent({
address: '0x1234567890123456789012345678901234567890',
onLogs: (logs) => {
console.log('Matching logs received:', logs);
},
onError: (error) => {
console.error('watchEvent error:', error);
},
});關閉碼與用戶端動作
當伺服器終止 WebSocket 工作階段時,會傳送帶有特定關閉碼與簡短原因的 Close 訊框。下表列出伺服器發出的關閉碼與建議動作:
| 關閉碼 | 原因字串 | 說明 | 可重試 | 用戶端動作 |
|---|---|---|---|---|
| 1001 | idle | 閒置連線,3600 秒(1 小時)內沒有訂閱或訊息 | 是 | 視需要重新連線。 |
| 1003 | binary frames are not accepted | 收到二進位 WebSocket 訊框;僅接受 UTF-8 文字訊框 | 否 | 不要自動重新連線。更新用戶端以傳送文字訊框。 |
| 1009 | message too large | 入站承載超過 1 MiB | 否 | 不要自動重新連線。拆分大型請求或縮小承載大小。 |
| 1012 | service restart | 伺服器正在重新啟動,或工作階段已達最大存續時間(24 小時) | 是 | 使用隨機抖動退避重新連線、重新建立訂閱,並回填遺漏的資料。 |
| 1013 | chain unavailable | 鏈無法使用 | 是 | 使用全抖動指數退避重新連線、重新建立訂閱,並回填遺漏的資料。 |
| 1013 | overloaded | 伺服器暫時過載 | 是 | 使用全抖動指數退避重新連線、重新建立訂閱,並回填遺漏的資料。 |
| 4402 | insufficient balance | 帳戶餘額已用盡 | 否 | 不要自動重新連線。儲值餘額後再重新連線。 |
| 4404 | invalid api key | API key 未知、已停用或已撤銷 | 否 | 不要自動重新連線。請先在控制台確認或輪替 API key,再重新連線。 |
| 4408 | slow consumer | 伺服器的推送佇列超過 512 KiB 時,會關閉工作階段並捨棄待處理的通知;用戶端可能收不到關閉訊框(瀏覽器回報 1006) | 是 | 將非預期的斷線(未收到關閉訊框,瀏覽器回報 1006)視同 4408:使用退避重新連線、重新建立訂閱,並以 eth_getLogs 回填被捨棄的資料;減少訂閱或加快讀取。 |
| 4429 | push rate exceeded | 通知速率超過每秒 1,000 次推送 | 是 | 減少訂閱或縮小篩選範圍;使用退避重新連線、重新訂閱並回填。 |
| 4503 | billing unavailable | 計費暫時無法使用 | 是 | 暫時狀態;使用全抖動指數退避重新連線。 |
重新連線與指數退避
為避免連線中斷時發生同步重新連線風暴,用戶端必須實作全抖動的指數退避:
- 退避公式:在第 n 次重新連線嘗試之前(n = 0, 1, 2, ...),等待一段均勻隨機選取的時長:
delay = random(0, min(20s, 0.5s * 2^n)) - 重設計數器:只有在維持不中斷的穩定連線至少
60 seconds後,才將重試計數器 n 重設為 0。 - 關閉碼 1012:在第一次重新連線嘗試前加入隨機初始延遲,以避免同步重新連線尖峰。
- 不可重試的關閉碼:遇到 4402、4404、1003 或 1009 時,請勿自動重新連線。
重新連線後回填遺漏的資料
WebSocket 訂閱不會跨連線持續存在;斷線期間發出的通知不會保留在伺服器上。重新連線後,用戶端應執行追趕策略:
- 使用
eth_getLogs回填日誌:- 持久化記錄已成功處理的最高區塊編號(
last_processed_block)。 - 重新連線後立即呼叫
eth_subscribe("logs", ...)以擷取即時事件。 - 透過
eth_getLogs查詢遺漏的區塊,設定fromBlock: last_processed_block + 1與toBlock: "latest"(或即時串流收到的第一個區塊)。 - 若斷線缺口超過該網路的
max_logs_block_range(來自GET /v1/chains),請將查詢切分為不超過該限制的區塊。 - 使用唯一元組
(blockHash, transactionHash, logIndex)在查詢邊界上去重日誌項目。
- 持久化記錄已成功處理的最高區塊編號(
- 使用
eth_getBlockByNumber回填區塊頭:- 記錄斷線前收到的最新區塊編號與雜湊。
- 重新訂閱
newHeads。 - 查詢
eth_getBlockByNumber("latest", false),並依序取得遺漏的中間區塊。驗證parentHash的鏈結連續性,以偵測重組。
限制
| 限制 | 值 | 超過時的結果 |
|---|---|---|
| 每條 WebSocket 連線的訂閱數 | 100 | -32022 subscription_limit |
每條 WebSocket 連線的 newHeads 訂閱數 | 4 | -32022 subscription_limit |
logs 訂閱篩選條件要求 | 必須指定 address 或 topic0(topics 中的第一個位置) | -32602 logs_filter_required |
下一步
最後更新: