本文介绍了如何在 QuickNode 上设置和测试方法特定的速率限制,以防止 API 滥用并优化资源使用。涵盖了速率限制的概念、配置方式以及测试示例,适合需要管理 API 使用的开发者和团队。
速率限制对于防止 API 滥用和确保你的端点资源保持在预期使用阈值内至关重要。QuickNode 提供灵活的方法速率限制机制,允许你对单个 API 方法设置准确的限制,从而控制特定端点调用的频率。本文将指导你如何在 QuickNode 端点上设置、测试和监控特定方法的速率限制,以优化和控制 API 使用。
让我们开始吧!
依赖项 | 版本 |
---|---|
node.js | ^18.16.0 |
axios | ^1.7.9 |
ethers | ^6.13.5 |
@solana/web3.js | ^2.0.0 |
基于 IP 的速率限制允许你控制从单个 IP 地址可以发出的请求总数,而不管调用的方法是什么。这提供了基本的保护以防止滥用,并帮助确保所有访问你端点的客户端之间的公平使用。
方法速率限制允许你为特定的 REST、RPC 或 gRPC 方法定义不同的请求限制。这种细粒度的控制有助于优化你端点的性能并有效管理成本。
eth_getBlock
、getAccountInfo
的请求数量)信息
注意:方法速率限制适用于请求而非响应。
你可以通过仪表板 UI 或以编程方式配置方法速率限制。
你还可以使用 控制台 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 端点。
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"}
*/
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 端点的性能和成本提供了强大的控制。通过精心配置这些限制并在你的应用程序中实施适当的处理,你可以确保最佳性能,同时保持对资源使用的控制。
如果你有任何问题或需要帮助,请随时通过我们的 Discord 或 Twitter 联系我们。
让我们知道 你对我们的反馈或对新主题的请求。我们很乐意听取你的意见。
- 原文链接: quicknode.com/guides/qui...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!