AddRateLimitHeadersMiddleware: cabeceras de limite
El middleware throttle detiene las peticiones cuando se supera el límite, pero los clientes no deberían tener que adivinar cuán cerca están. Para eso está AddRateLimitHeadersMiddleware: transparencia completa mediante cabeceras HTTP, permitiendo que los clientes inteligentes se autorregulen antes de chocar.
Tras generarse la respuesta, este middleware lee el estado del limitador y añade cuatro cabeceras críticas:
X-RateLimit-Limit: el máximo de peticiones permitidas en la ventana (por ejemplo, 60)X-RateLimit-Remaining: cuántas quedan en la ventana actualX-RateLimit-Reset: marca de tiempo Unix de cuándo se reinicia la cuotaRetry-After: sólo cuando se supera el límite; dice cuántos segundos esperar antes de reintentar
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
$token = $request->bearerToken() ?? $request->ip();
$key = 'api-token:'.$token;
$maxAttempts = 60;
$remainingAttempts = $this->limiter->remaining($key, $maxAttempts);
$retryAfter = $this->limiter->availableIn($key);
$response->headers->set('X-RateLimit-Limit', (string) $maxAttempts);
$response->headers->set('X-RateLimit-Remaining', (string) max(0, $remainingAttempts));
if ($remainingAttempts <= 0) {
$response->headers->set('X-RateLimit-Reset', (string) (time() + $retryAfter));
$response->headers->set('Retry-After', (string) $retryAfter);
}
return $response;
}
La idea clave: X-RateLimit-Remaining está disponible en todas las respuestas, no sólo en los rechazos. Eso permite a los clientes vigilar su cuota continuamente, aunque estén lejísimos del límite.
Clientes reactivos (mal diseñados):
- Envían peticiones sin más
- Reciben un 429
- Esperan los segundos de
Retry-After - Reintentan
Es un desperdicio: queman peticiones hasta chocar con el muro.
Clientes proactivos (bien diseñados):
- Envían una petición
- Leen
X-RateLimit-Remaining: 5en las cabeceras - Bajan su ritmo
- Aflojan antes de llegar a cero
Ni siquiera llegan a disparar el límite, porque se autorregulan. Tu API está más contenta porque no rechaza peticiones. El cliente está más contento porque recibe servicio constante.
El límite es complicado con clientes concurrentes. Imagina un cliente que lanza treinta peticiones a la vez. La primera ve 60 − 30 = 30 restantes. Pero para cuando las treinta llegan a tu API, el contador ya ha bajado. Los clientes deben entender que X-RateLimit-Remaining es una instantánea, no una garantía. Es exacta en ese momento, no en el futuro.
Por eso los clientes listos usan esa cabecera como guía y no como ley. Puede que aflojen al llegar a diez restantes en lugar de a cero, dándose un margen de seguridad para la concurrencia.
Muchas librerías HTTP leen ya estas cabeceras automáticamente e implementan estrategias de espera. Al exponerlas, habilitas comportamiento sofisticado en el cliente sin tener que construirlo tú.