如何使用QuickNode设置方法速率限制

  • QuickNode
  • 发布于 2025-02-07 16:58
  • 阅读 25

本文介绍了如何在 QuickNode 上设置和测试方法特定的速率限制,以防止 API 滥用并优化资源使用。涵盖了速率限制的概念、配置方式以及测试示例,适合需要管理 API 使用的开发者和团队。

概述

速率限制对于防止 API 滥用和确保你的端点资源保持在预期使用阈值内至关重要。QuickNode 提供灵活的方法速率限制机制,允许你对单个 API 方法设置准确的限制,从而控制特定端点调用的频率。本文将指导你如何在 QuickNode 端点上设置、测试和监控特定方法的速率限制,以优化和控制 API 使用。

让我们开始吧!

你将需要的条件

  • 了解如何与区块链 RPC 方法交互
  • 一个 QuickNode 账户(在此 创建一个免费账户
  • 一个 QuickNode 端点
  • 已安装 Node.js
  • 一个终端窗口

你将要做的事情

  • 了解 QuickNode 的速率限制
  • 通过 QuickNode 仪表板配置速率限制
  • 使用 Ethereum 和 Solana 的不同方法测试速率限制
依赖项 版本
node.js ^18.16.0
axios ^1.7.9
ethers ^6.13.5
@solana/web3.js ^2.0.0

基于 IP 的速率限制

基于 IP 的速率限制允许你控制从单个 IP 地址可以发出的请求总数,而不管调用的方法是什么。这提供了基本的保护以防止滥用,并帮助确保所有访问你端点的客户端之间的公平使用。

理解 IP 速率限制

  • 限制适用于来自一个 IP 地址的请求总数
  • 可以为不同的时间间隔设定限制(每秒、每分钟或每天)
  • 除非存在更具体的方法限制,否则会适用于所有方法

按方法速率限制

方法速率限制允许你为特定的 REST、RPC 或 gRPC 方法定义不同的请求限制。这种细粒度的控制有助于优化你端点的性能并有效管理成本。

理解方法速率限制

  • 为单独的 RPC 方法设置唯一限制(例如,控制你可以对 eth_getBlockgetAccountInfo 的请求数量)
  • 控制每个方法的请求频率(例如,每秒/每分钟/每天的请求)

HTTP 协议注意事项

  • 速率限制适用于所有 HTTP POST 请求
  • 每个方法调用都算作其特定限制
  • 同步响应算作单个请求

WebSocket (WSS) 协议注意事项

  • 限制适用于初始订阅请求
  • 订阅响应不计入限制

信息

注意:方法速率限制适用于请求而非响应。

如何设置方法速率限制

你可以通过仪表板 UI 或以编程方式配置方法速率限制。

仪表板方法

  1. 登录你的 QuickNode 仪表板
  2. 选择你的端点(如果尚未创建,请为 Ethereum 或 Solana 主网创建一个)
  3. 导航到 安全性 选项卡
  4. 找到 方法限制 部分以自定义你的速率限制

QuickNode 方法限制

控制台 API 方法

你还可以使用 控制台 API 以编程方式管理方法速率限制。以下是一些常见操作:

  • 获取限制
  • 更新速率限制
  • 更新方法限制
  • 删除限制

获取方法速率限制。

curl -X 'GET' \
  'https://api.quicknode.com/v0/endpoints/{id}/method-rate-limits' \
  -H 'accept: application/json' \
  -H 'x-api-key: YOUR_API_KEY'

更新速率限制。

curl -X 'PUT' \
  'https://api.quicknode.com/v0/endpoints/{id}/rate-limits' \
  -H 'accept: */*' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "rate_limits": {
      "rps": 300
    }
}'

更新方法速率限制。

curl -X 'PATCH' \
  'https://api.quicknode.com/v0/endpoints/{id}/method-rate-limits/{method_rate_limit_id}' \
  -H 'accept: application/json' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
  "methods": [\
    "eth_getlogs"\
  ],
  "status": "enabled",
  "rate": 20
}'

删除方法速率限制。

curl -X 'DELETE' \
  'https://api.quicknode.com/v0/endpoints/{id}/method-rate-limits/{method_rate_limit_id}' \
  -H 'accept: application/json' \
  -H 'x-api-key: YOUR_API_KEY'

{id} 替换为你的端点 ID,将 {method_rate_limit_id} 替换为你想要修改或删除的特定速率限制 ID。

在添加新的方法速率限制时,你需要指定确切的 RPC 方法名称并设置请求频率。你可以配置每秒、每分钟或每天的限制。对于本指南,我们将设置以下测试配置:

  • Ethereum

  • Solana

  • eth_blockNumber:每分钟 1 个请求

  • eth_subscribe:每分钟 1 个请求

  • getSlot:每分钟 1 个请求

  • accountSubscribe:每分钟 1 个请求

出于本指南的目的,设置上述每个方法的速率限制(根据你偏好的链选择)。一旦设置,它将在你的仪表板中显示如下:

方法速率限制

现在,让我们创建脚本来测试方法速率限制。

测试你的速率限制

让我们创建一个简单的 Node.js 脚本来测试我们的速率限制。首先,创建一个文件夹,初始化 npm 项目并创建测试文件:

mkdir rate-limits
cd rate-limits
npm init --y
npm install axios ethers @solana/web3.js@2
echo > http.js
echo > wss.js

然后,更新你的 package.json 以使用 "type":"module",以便你可以使用导入语句(例如,import { ethers } from 'ethers)。

现在,我们将演示在超过你配置的限制时会发生什么。在此示例中,我们将使用 eth_blockNumber 方法和 eth_subscribe 的每分钟 1 个请求的速率限制(如上所述)。

将代码添加到每个适当的文件中,请记得在测试 HTTP 端点时将 YOUR_QUICKNODE_HTTP_ENDPOINT 替换为你的实际 HTTP 端点,在测试 WSS 端点时将其替换为 WSS 端点。

Ethereum

  • HTTP (eth_blockNumber)
  • WebSocket (eth_subscribe)
const axios = require('axios');

const QUICKNODE_ENDPOINT = 'YOUR_QUICKNODE_HTTP_ENDPOINT';

async function makeRequest() {
const payload = {
    jsonrpc: '2.0',
    id: 1,
    method: 'eth_blockNumber',
    params: []
};

try {
    const response = await axios.post(QUICKNODE_ENDPOINT, payload);
    console.log(`[${new Date().toISOString()}] 成功:`,
    parseInt(response.data.result));
    return true;
} catch (error) {
    if (error.response?.status === 429) {
    console.log(`[${new Date().toISOString()}] 超过速率限制。 ` +
        `请在 ${error.response.headers['retry-after']} 秒后再试`);
    } else {
    console.error(`[${new Date().toISOString()}] 错误:`, error.message);
    }
    return false;
}
}

async function demonstrateRateLimit() {
console.log('发出第一次请求 - 应该成功');
await makeRequest();

console.log('\n立即发出第二次请求 - 应该失败');
await makeRequest();

console.log('\n等待 60 秒...');
await new Promise(resolve => setTimeout(resolve, 60000));

console.log('\n等待后发出请求 - 应该成功');
await makeRequest();
}

demonstrateRateLimit();

/* 示例输出:

发出第一次请求 - 应该成功
[2025-01-30T19:15:05.703Z] 成功: 21739376

立即发出第二次请求 - 应该失败
[2025-01-30T19:15:05.817Z] 超过速率限制。请在未定义秒后再试

等待 60 秒...

等待后发出请求 - 应该成功
[2025-01-30T19:16:06.140Z] 成功: 21739381

*/
import { ethers } from 'ethers';

const QUICKNODE_WSS_ENDPOINT = 'YOUR_QUICKNODE_WSS_ENDPOINT';

async function demonstrateWebSocketRateLimit() {
    let provider = new ethers.WebSocketProvider(QUICKNODE_WSS_ENDPOINT);

    try {
        console.log('[WS] 已连接,尝试第一次订阅');

        const firstSubId = await provider.send('eth_subscribe', ['newHeads']);
        console.log(`[${new Date().toISOString()}] 第一次订阅已创建:`, firstSubId);

        await new Promise(resolve => setTimeout(resolve, 2000));

        await provider.destroy();
        console.log('[WS] 第一次连接已销毁');

        provider = new ethers.WebSocketProvider(QUICKNODE_WSS_ENDPOINT);
        console.log('[WS] 重新连接,尝试第二次订阅');

        const secondSubId = await provider.send('eth_subscribe', ['newPendingTransactions']);
        console.log(`[${new Date().toISOString()}] 第二次订阅已创建:`, secondSubId);

    } catch (error) {
        if (error.code === -32029) {
            console.log('超过速率限制。请在 1 分钟后再试。');
        }
        console.error(`[${new Date().toISOString()}] 错误:`, error.message);
    }

    provider.websocket.on('message', (data) => {
        console.log(`[${new Date().toISOString()}] 接收到消息:`, data.toString());
    });

    provider.websocket.on('error', (error) => {
        console.error('[WS] 错误:', error);
    });
}

demonstrateWebSocketRateLimit()
    .catch(error => console.error('致命错误:', error));

/* 示例输出:
[WS] 已连接,尝试第一次订阅
[2025-02-03T15:52:44.778Z] 第一次订阅已创建: 0x1820bda339b97d450000000000002285
[WS] 第一次连接已销毁
[WS] 重新连接,尝试第二次订阅
[2025-02-03T15:52:47.218Z] 错误: 无法合并错误 (错误={ "code": -32011, "message": "请求限制已达" }, 载荷={ "id": 1, "jsonrpc": "2.0", "method": "eth_subscribe", "params": [ "newPendingTransactions" ] }, code=UNKNOWN_ERROR, version=6.13.5)
[2025-02-03T15:52:47.218Z] 接收到的消息: {"jsonrpc":"2.0","id":2,"result":"0x1"}
*/

Solana

  • HTTP (getAccountInfo)
  • WebSocket (accountSubscribe)
import { createSolanaRpc, address } from "@solana/web3.js";

const ENDPOINT = "YOUR_QUICKNODE_HTTP_ENDPOINT";
const ACCOUNT = "7cVfgArCheMR6Cs4t6vz5rfnqd56vZq4ndaBrY5xkxXy";

async function testRateLimit() {
    const solanaRpc = createSolanaRpc(ENDPOINT);
    const searchAddress = address(ACCOUNT);

    try {
        console.log(`[${new Date().toISOString()}] 第一次请求`);
        const { value: accountInfo1 } = await solanaRpc.getAccountInfo(searchAddress).send();
        console.log('第一次响应:', accountInfo1);
    } catch (e) {
        console.error('第一次请求错误:', e);
    }

    try {
        console.log(`[${new Date().toISOString()}] 第二次请求`);
        const { value: accountInfo2 } = await solanaRpc.getAccountInfo(searchAddress).send();
        console.log('第二次响应:', accountInfo2);
    } catch (e) {
        console.error('第二次请求错误:', e);
    }
}

testRateLimit()
    .catch(console.error)
    .finally(() => {
        console.log('测试完成');
        process.exit(0);
    });

    /*
    [2025-02-03T16:48:35.521Z] 第一次请求
    第一次响应: {
    data: '',
    executable: false,
    lamports: 697460654305n,
    owner: '11111111111111111111111111111111',
    rentEpoch: 18446744073709551615n,
    space: 0n
    }

    [2025-02-03T16:48:35.835Z] 第二次请求
    第二次请求错误: SolanaError: HTTP 错误 (429): 请求过多
    at makeHttpRequest
    */
import { createSolanaRpcSubscriptions, address } from "@solana/web3.js";

const ENDPOINT = 'YOUR_QUICKNODE_WSS_ENDPOINT';
const ACCOUNT = '7cVfgArCheMR6Cs4t6vz5rfnqd56vZq4ndaBrY5xkxXy';

async function testRateLimit() {
    let rpcSubscriptions = createSolanaRpcSubscriptions(ENDPOINT);
    const accountAddress = address(ACCOUNT);
    const abortController1 = new AbortController();

    try {
        console.log(`[${new Date().toISOString()}] 第一次订阅尝试`);
        const sub1 = await rpcSubscriptions.accountNotifications(accountAddress, {
            commitment: 'confirmed',
            encoding: 'base64'
        }).subscribe({ abortSignal: abortController1.signal });

        for await (const notification of sub1) {
            console.log('第一次订阅更新:', notification.value);
            break;
        }
    } finally {
        abortController1.abort();
        await rpcSubscriptions.dispose();
    }

    await new Promise(resolve => setTimeout(resolve, 1000));

    rpcSubscriptions = createSolanaRpcSubscriptions(ENDPOINT);
    const abortController2 = new AbortController();

    try {
        console.log(`[${new Date().toISOString()}] 第二次订阅尝试`);
        const sub2 = await rpcSubscriptions.accountNotifications(accountAddress, {
            commitment: 'confirmed',
            encoding: 'base64'
        }).subscribe({ abortSignal: abortController2.signal });

        for await (const notification of sub2) {
            console.log('第二次订阅更新:', notification.value);
            break;
        }
    } catch (e) {
        console.error('第二次订阅错误:', e);
    } finally {
        abortController2.abort();
        await rpcSubscriptions.dispose();
    }
}

testRateLimit()
    .catch(console.error)
    .finally(() => {
        console.log('测试完成');
        process.exit(0);
    });

    /*
    [2025-02-03T16:52:31.806Z] 第一次订阅尝试
    第一次订阅更新: {
    lamports: 697856097133n,
    data: [ '', 'base64' ],
    owner: '11111111111111111111111111111111',
    executable: false,
    rentEpoch: 18446744073709551615n,
    space: 0n
    }
    [2025-02-03T16:52:48.098Z] 第二次订阅尝试
    第二次订阅错误: SolanaError: 此节点无法提供交易历史
    */

运行每个脚本(记得输入你的端点 URL)并分析输出。你应该看到第一次请求通过,第二次请求失败(因为它触发了方法速率限制)。注意:这不会限制响应的速率**。

就是这样!你刚刚学会了如何在 EVM 和 SVM 区块链上设置和测试方法速率限制。

监控和故障排除

QuickNode 仪表板提供了在 分析 选项卡下的监控。你可以在此跟踪特定方法的使用,识别响应状态并随时间进行细分。利用该信息优化你的速率限制并了解你应用程序的行为。此外,你还可以使用 控制台 API 查看有关你的端点和使用情况的详细指标。

其他资源

想了解更多关于保护你的端点的信息?查看以下指南:

结束语

方法速率限制为你 QuickNode 端点的性能和成本提供了强大的控制。通过精心配置这些限制并在你的应用程序中实施适当的处理,你可以确保最佳性能,同时保持对资源使用的控制。

如果你有任何问题或需要帮助,请随时通过我们的 DiscordTwitter 联系我们。

我们 ❤️ 反馈!

让我们知道 你对我们的反馈或对新主题的请求。我们很乐意听取你的意见。

  • 原文链接: quicknode.com/guides/qui...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。