当前位置:首页 > PHP

php实现频率限制

2026-02-16 13:09:41PHP

实现频率限制的基本方法

在PHP中实现频率限制(Rate Limiting)可以通过多种方式完成,核心目标是限制用户在特定时间内的请求次数。以下是几种常见的方法:

使用Redis存储计数 Redis是高频场景下的理想选择,支持原子操作和过期时间。通过INCREXPIRE命令组合实现计数:

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'user:' . $userId . ':requests';
$limit = 100; // 限制次数
$window = 3600; // 时间窗口(秒)

$current = $redis->incr($key);
if ($current === 1) {
    $redis->expire($key, $window);
}
if ($current > $limit) {
    header('HTTP/1.1 429 Too Many Requests');
    exit;
}

数据库记录方式 适用于无Redis的环境,通过MySQL记录请求时间戳:

// 清理过期记录
$db->query("DELETE FROM rate_limit WHERE timestamp < NOW() - INTERVAL 1 HOUR");

// 检查当前计数
$count = $db->query("SELECT COUNT(*) FROM rate_limit WHERE user_id = $userId")->fetchColumn();
if ($count >= 100) {
    header('HTTP/1.1 429 Too Many Requests');
    exit;
}

// 记录新请求
$db->query("INSERT INTO rate_limit (user_id, timestamp) VALUES ($userId, NOW())");

滑动窗口算法优化

固定窗口可能在窗口边界出现流量突增,滑动窗口通过时间范围精确控制:

$window = 60; // 60秒窗口
$now = microtime(true);
$oldest = $now - $window;

// 移除旧记录
$redis->zRemRangeByScore('requests', 0, $oldest);

// 添加当前请求并检查总数
$redis->zAdd('requests', $now, uniqid());
if ($redis->zCard('requests') > 30) { // 限制30次/分钟
    header('Retry-After: ' . $window);
    die('Rate limit exceeded');
}

Token Bucket算法实现

适用于需要平滑流量的场景,使用漏桶或令牌桶算法:

$bucketKey = 'user:' . $userId . ':tokens';
$capacity = 10; // 桶容量
$refillRate = 1; // 每秒补充1个令牌

$lastChecked = $redis->hGet($bucketKey, 'last_checked') ?: time();
$tokens = $redis->hGet($bucketKey, 'tokens') ?: $capacity;

$now = time();
$elapsed = $now - $lastChecked;
$tokens += $elapsed * $refillRate;
$tokens = min($tokens, $capacity);

if ($tokens < 1) {
    header('HTTP/1.1 429 Too Many Requests');
    exit;
}

$tokens--;
$redis->hMSet($bucketKey, [
    'last_checked' => $now,
    'tokens' => $tokens
]);

中间件封装方案

在框架(如Laravel)中可通过中间件统一处理:

namespace App\Http\Middleware;

use Closure;
use Illuminate\Cache\RateLimiter;
use Symfony\Component\HttpFoundation\Response;

class ThrottleRequests
{
    public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1)
    {
        $key = $request->ip();
        if (app(RateLimiter::class)->tooManyAttempts($key, $maxAttempts)) {
            return new Response('Too Many Attempts', 429);
        }
        app(RateLimiter::class)->hit($key, $decayMinutes * 60);
        return $next($request);
    }
}

HTTP头部与缓存控制

返回标准HTTP状态码和头部信息:

php实现频率限制

header('X-RateLimit-Limit: 100');
header('X-RateLimit-Remaining: ' . ($limit - $current));
header('Retry-After: ' . $window); // 429响应时提示重试时间

分布式系统注意事项

在分布式环境中需确保时钟同步,或使用集中式存储(如Redis)。避免本地内存计数导致限制失效。

标签: 频率php
分享给朋友:

相关文章

php实现表单

php实现表单

PHP 表单基础实现 创建一个简单的 PHP 表单需要 HTML 表单结构和 PHP 处理脚本。以下是一个完整的示例: HTML 表单部分 (form.html) <form action=…

php 实现接口

php 实现接口

PHP 实现接口的方法 在 PHP 中,接口(Interface)用于定义一组方法的规范,而不包含具体的实现。类可以实现(implement)接口,并必须实现接口中定义的所有方法。 定义接口 接口通…

php 实现下载

php 实现下载

PHP 实现文件下载的方法 使用 PHP 实现文件下载可以通过设置 HTTP 头信息,强制浏览器将文件作为附件下载而非直接打开。 基本下载实现 $file_path = 'path/to/your/…

php实现定时

php实现定时

PHP 实现定时任务的方法 PHP 本身是脚本语言,通常需要借助外部工具或框架实现定时任务。以下是几种常见方法: 使用 Cron 任务 Linux 系统自带的 Cron 是常用的定时任务工具。通过编…

php实现伪静态

php实现伪静态

PHP 实现伪静态的方法 伪静态(URL Rewrite)是一种将动态URL转换为看似静态URL的技术,提升SEO友好性和用户体验。以下是几种常见的实现方式: 使用 Apache 的 mod_rew…

php变量的实现

php变量的实现

PHP变量的实现机制 PHP变量的实现基于Zend引擎的底层数据结构。核心结构体zval用于存储变量类型和值,其设计允许动态类型转换和高效内存管理。 zval结构体 PHP变量通过zval结构体实现…