2010-11-23 218 views
9

我使用各种第三方Web API,其中许多都强制限速。如果有一个相当普通的PHP库,我可以用它来限制我的调用,这将是非常有用的。我可以想出几种方法来做到这一点,也许可以将呼叫放入队列中,并且可以打电话的时间戳,但是如果其他人已经做得很好,我希望避免重新发明车轮。PHP限速客户端

+1

限制API调用或字节传输的数量? – stillstanding 2010-11-23 15:37:14

+0

API调用次数。 – 2010-11-25 04:13:39

回答

2

我不能拿信誉,但我使用这种方法,因为没有'通用'软件包 - 但我想你可以根据你的编码方法做到这一点。

How do I throttle my site's API users?

+1

这看起来是服务器端,我如何扼杀其他人对我的API的使用 - 最终有用,不要误会我 - 但我需要将自己的呼叫限制到其他人的服务器。 (除非你指的是代码片段,看起来它可能是客户端,实际上这可能接近我的需要。) – 2010-11-25 04:17:18

1

作为替代,我(过去)创建的存储API调用,所以如果我尝试再次进行相同的调用,在特定的时间范围内的“缓存”的文件夹,它首先从缓存中抓取(更加无缝),直到可以拨打新电话。可能会在短期内收到归档信息,但可以帮助您避免API长期阻挡您。

+0

缓存只有在我使用相同参数调用给定的API时才有用。这是朝着正确方向迈出的一步,但我会经常变化参数并期待不同的结果。另外,一些API禁止在其TOS中进行缓存。 – 2010-11-25 04:15:08

5

我意识到这是一个古老的线程,但认为我会发布我的解决方案,因为它基于我在SE上发现的其他东西。我花了一段时间寻找自己的答案,但很难找到一些好的东西。它基于here讨论的Python解决方案,但我添加了对可变大小请求的支持,并使用PHP闭包将其转换为函数生成器。

function ratelimiter($rate = 5, $per = 8) { 
    $last_check = microtime(True); 
    $allowance = $rate; 

    return function ($consumed = 1) use (
    &$last_check, 
    &$allowance, 
    $rate, 
    $per 
) { 
    $current = microtime(True); 
    $time_passed = $current - $last_check; 
    $last_check = $current; 

    $allowance += $time_passed * ($rate/$per); 
    if ($allowance > $rate) 
     $allowance = $rate; 

    if ($allowance < $consumed) { 
     $duration = ($consumed - $allowance) * ($per/$rate); 
     $last_check += $duration; 
     usleep($duration * 1000000); 
     $allowance = 0; 
    } 
    else 
     $allowance -= $consumed; 

    return; 
    }; 
} 

它可以用来限制任何东西。下面是在每8秒的默认五“请求”限制了简单的声明一个愚蠢的例子:

$ratelimit = ratelimiter(); 
while (True) { 
    $ratelimit(); 
    echo "foo".PHP_EOL; 
} 

下面是我使用它在基于每600秒600个请求限制对Facebook的图形API批处理请求在批次的大小:

$ratelimit = ratelimiter(600, 600); 
while (..) { 
    .. 

    $ratelimit(count($requests)); 
    $response = (new FacebookRequest(
    $session, 'POST', '/', ['batch' => json_encode($requests)] 
))->execute(); 

    foreach ($response->..) { 
    .. 
    } 
} 

希望这可以帮助别人!

4

您可以使用token bucket algorithm进行速率限制。我在PHP中实现了这个功能:bandwidth-throttle/token-bucket

use bandwidthThrottle\tokenBucket\Rate; 
use bandwidthThrottle\tokenBucket\TokenBucket; 
use bandwidthThrottle\tokenBucket\storage\FileStorage; 

$storage = new FileStorage(__DIR__ . "/api.bucket"); 
$rate = new Rate(10, Rate::SECOND); 
$bucket = new TokenBucket(10, $rate, $storage); 
$bucket->bootstrap(10); 

if (!$bucket->consume(1, $seconds)) { 
    http_response_code(429); 
    header(sprintf("Retry-After: %d", floor($seconds))); 
    exit(); 
}