Discord Webhook 速率限制

12
我正在开发一个私人浏览器扩展程序,它从网页中提取一些信息,并通过Webhook将其发布到Discord频道中。
浏览器扩展程序会评估“x-ratelimit-…”响应头以观察速率限制限制。
在进行“垃圾邮件测试”时,似乎速率限制限制得到了正确的尊重,到目前为止一切都正常。但是,即使“ratelimit-remaining”大于“0”,在发送一堆消息(15+)后仍然偶尔会出现速率限制。
为了解决这个问题,我已经在“ratelimit-remaining”为“1”时停止,并在“ratelimit-reset”时间戳中添加了额外的一秒钟。但这似乎没有帮助。
let rateLimitRemaining = 5;
let rateLimitReset = 0;

function sendContent()
{
    if ( contentQueue.length > 0 )
    {
        console.log( "Messages in content queue: " + contentQueue.length );

        let content = contentQueue[ 0 ];
        let dateTimestamp = getCurrentUTCTimestamp();

        // Don't send if remaining rate limit is <= 1 and current UTC time is less than reset timestamp
        if ( rateLimitRemaining <= 1 && dateTimestamp <= rateLimitReset )
            return;

        contentQueue.shift();

        let url = "...";
        sendMessage( content, url );
    }
}

function sendMessage( content, url )
{
    let payload = JSON.stringify( { "content": content } );
    $.ajax(
    {
        contentType: 'application/json',
        method: "POST",
        url: url,
        data: payload,
        dataType: 'json'
    } ).done( function( response, status, jqXHR )
    {
        rateLimitRemaining = parseInt( jqXHR.getResponseHeader( 'x-ratelimit-remaining' ) );
        // Add an additional second to the reset timestamp
        rateLimitReset = parseInt( jqXHR.getResponseHeader( 'x-ratelimit-reset' ) ) + 1;

        let timeToResetRemaining = rateLimitReset - getCurrentUTCTimestamp();
        console.log( '[' + getCurrentDateTime() + '] Content sent to webhook. Remaining until rate limit: ' + rateLimitRemaining + ' / Reset @ ' + rateLimitReset + ' (' + getCurrentUTCTimestamp() + ') (' + timeToResetRemaining + ')' );
    } ).fail( function( jqXHR, status, error )
    {
        let response = jqXHR.responseJSON;

        // If we got rate limited, respect the retry_after delay
        if ( response.hasOwnProperty( 'message' ) && response.message.indexOf( 'rate limited' ) !== 0 )
        {
            rateLimitRemaining = 0;
            rateLimitReset = getCurrentUTCTimestamp() + Math.ceil( response.retry_after / 1000 ) + 1;
        }

        console.log( '[' + getCurrentDateTime() + '] Error sending request to webhook.' );
        console.log( response );
    } );
}

即使剩余请求数量为3,仍然受到了请求限制

同样的请求触发了请求限制,但是x-ratelimit-remaining响应头的值大于0,这也很奇怪。

请求限制响应头中的值大于0

我错在哪里了?我需要考虑x-ratelimit-bucketx-ratelimit-reset-after吗?


也许我没有正确理解你想做什么,但是 if ( rateLimitRemaining <= 1 && dateTimestamp <= rateLimitReset ) 这行代码正确吗?rateLimitReset 不应该在之前定义吗? - 19mike95
@19mike95 rateLimitReset 在代码的第2行被定义和初始化。:) let rateLimitReset = 0; - Mario Werner
2个回答

1
一个不发送机器人令牌的Webhook受到与其他API调用不同的速率限制。每个频道每分钟最多可以发送一定数量的Webhook消息,这个限制是共享的,因此其他机器人和服务可能会影响您交付Webhook的能力。目前这个限制是每分钟30条消息,但并未记录下来。之前Discord开发者曾推文提到过这个限制:https://twitter.com/lolpython/status/967621046277820416。第二个限制是每个IP的限制,您可以自行监测并防止出现429错误。您需要监测请求返回的头信息来管理这个限制。除此之外,还有一个最终限制,即每个IP每秒50个请求,https://blog.xenon.bot/handling-rate-limits-at-scale-fb7b453cb235 - 这是由Cloudflare强制执行的。如果您有更多问题,请告诉我!

谢谢提供这些信息,非常有帮助。该项目始于2019年,已经到达了其生命周期终点。因此,很遗憾我无法再验证是否能够解决问题。 - Mario Werner

0

根据Discord开发者文档,头部中的速率限制不为零似乎有些奇怪。不确定您的应用程序是否是这种情况,但它确实提到“控制表情符号的路由不遵循正常的速率限制约定。这些路由特别限制在每个公会的基础上,以防止滥用。这意味着我们的API返回的配额可能不准确,您可能会遇到429错误。”。

开发者文档指出,您应该依赖Retry-After头或retry-after字段来确定重试时间,因此最好这样做而不是使用其他头部。无论剩余头部是否可用,API速率限制的更好模式是将所有查询添加到队列中,在成功时从队列中删除,在失败时使用429状态设置队列的超时时间,该时间基于Retry-After头。这将确保您的请求继续得到处理。您肯定可以在浏览器端JavaScript中执行此操作,但我将其留给读者作为练习,因为这可能不是最佳方法(请参见下文)。

如果你计划让其他人使用这段代码或发布它,那么你不应该直接从浏览器调用API,因为这会给予对你的Webhook凭证的访问权限。相反,让你的浏览器对服务器进行身份验证,然后保持你的Webhook凭证隐藏。如果你要在服务器上使用node.js,我建议使用discord.js SDK,它可以自动处理速率限制。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接