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 Chainwss://api.blockvectra.com/v1/robinhood_mainnet/{api_key}
Robinhood Chain Testnetwss://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 訊框。下表列出伺服器發出的關閉碼與建議動作:

關閉碼原因字串說明可重試用戶端動作
1001idle閒置連線,3600 秒(1 小時)內沒有訂閱或訊息是視需要重新連線。
1003binary frames are not accepted收到二進位 WebSocket 訊框;僅接受 UTF-8 文字訊框否不要自動重新連線。更新用戶端以傳送文字訊框。
1009message too large入站承載超過 1 MiB否不要自動重新連線。拆分大型請求或縮小承載大小。
1012service restart伺服器正在重新啟動,或工作階段已達最大存續時間(24 小時)是使用隨機抖動退避重新連線、重新建立訂閱,並回填遺漏的資料。
1013chain unavailable鏈無法使用是使用全抖動指數退避重新連線、重新建立訂閱,並回填遺漏的資料。
1013overloaded伺服器暫時過載是使用全抖動指數退避重新連線、重新建立訂閱,並回填遺漏的資料。
4402insufficient balance帳戶餘額已用盡否不要自動重新連線。儲值餘額後再重新連線。
4404invalid api keyAPI key 未知、已停用或已撤銷否不要自動重新連線。請先在控制台確認或輪替 API key,再重新連線。
4408slow consumer伺服器的推送佇列超過 512 KiB 時,會關閉工作階段並捨棄待處理的通知;用戶端可能收不到關閉訊框(瀏覽器回報 1006)是將非預期的斷線(未收到關閉訊框,瀏覽器回報 1006)視同 4408:使用退避重新連線、重新建立訂閱,並以 eth_getLogs 回填被捨棄的資料;減少訂閱或加快讀取。
4429push rate exceeded通知速率超過每秒 1,000 次推送是減少訂閱或縮小篩選範圍;使用退避重新連線、重新訂閱並回填。
4503billing 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 訂閱不會跨連線持續存在;斷線期間發出的通知不會保留在伺服器上。重新連線後,用戶端應執行追趕策略:

  1. 使用 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) 在查詢邊界上去重日誌項目。
  2. 使用 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

下一步

最後更新:

本頁目錄