2010-11-23 211 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(); 
}