Throttler (요청 속도 제한)
CI4 내장 Throttler로 IP 기반 API Rate Limiting을 구현하는 방법을 학습합니다.
카운터가 초기화됐습니다.
Rate Limit 데모 — IP당 10초에 5회
버튼을 연속으로 눌러 한도를 초과하면 429 Too Many Requests 응답을 확인할 수 있습니다.
설정:
CAPACITY=5 / SECONDS=10 — 10초 윈도우에 최대 5회 허용.
한도 초과 시 Retry-After 헤더와 함께 429 반환.
Throttler::check()
check()는 토큰 버킷 알고리즘 기반으로 요청을 제한합니다. false를 반환하면 한도 초과입니다.
$throttler = service('throttler');
// check(키, 최대횟수, 시간(초), 비용=1)
// → IP당 1분에 60회 허용
if (! $throttler->check($request->getIPAddress(), 60, MINUTE)) {
return $response
->setStatusCode(429)
->setHeader('Retry-After', (string) $throttler->getTokenTime())
->setJSON(['error' => 'Too Many Requests']);
}
// 남은 재시도 대기 시간(초)
$retryAfter = $throttler->getTokenTime();
토큰 버킷 알고리즘
- 버킷에 capacity개의 토큰이 있습니다.
- 요청마다 cost개의 토큰을 소비합니다.
- 토큰은
seconds / capacity초마다 1개씩 자동 충전됩니다. - 버킷이 비면
false반환 → 429 응답.
ThrottleFilter — 라우트 그룹에 적용
app/Filters/ThrottleFilter.php
namespace App\Filters;
use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
class ThrottleFilter implements FilterInterface
{
public function before(RequestInterface $request, $arguments = null)
{
$throttler = service('throttler');
// IP당 1분에 60회
if (! $throttler->check($request->getIPAddress(), 60, MINUTE)) {
return service('response')
->setStatusCode(429)
->setHeader('Retry-After', (string) $throttler->getTokenTime())
->setJSON(['error' => 'Too Many Requests']);
}
}
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) {}
}
app/Config/Filters.php — 필터 등록
public array $aliases = [
'throttle' => \App\Filters\ThrottleFilter::class,
];
app/Config/Routes.php — API 라우트에 적용
$routes->group('api', ['filter' => 'throttle'], function ($routes) {
$routes->get('users', 'Api\Users::index');
$routes->post('users', 'Api\Users::create');
$routes->get('users/(:num)', 'Api\Users::show/$1');
});
필터 방식을 쓰면 컨트롤러 코드를 건드리지 않고 라우트 단위로 Rate Limit을 적용할 수 있어 API 보호에 적합합니다.