当前位置:首页 > 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和MySQL实现基础的搜索功能需要结合表单提交与数据库查询。创建一个HTML表单用于接收用户输入的搜索关键词,通过PHP处理表单数据并查询数据库。 // 搜索表单 (HT…

php记住密码怎么实现

php记住密码怎么实现

使用Cookie实现记住密码功能 在PHP中,可以通过设置Cookie来记住用户的登录状态。以下是一个简单的实现方式: // 用户登录验证成功后 if ($login_success) {…

php如何实现直播

php如何实现直播

实现直播功能的方法 PHP可以通过结合其他技术和工具来实现直播功能。以下是几种常见的方法: 使用流媒体服务器 配置流媒体服务器如Nginx-RTMP、Red5或Wowza。这些服务器支持RTMP协…

php 实现购物车

php 实现购物车

PHP 实现购物车功能 购物车功能是电子商务网站的核心部分,可以通过 PHP 和 Session 或数据库来实现。以下是两种常见的实现方式: 使用 Session 存储购物车数据 Session 是…

php实现上传图片

php实现上传图片

上传图片的基本流程 PHP 实现图片上传功能需要处理文件接收、验证、保存等步骤。以下是具体实现方法。 创建 HTML 表单 在 HTML 中创建一个表单,设置 enctype="multipart/…

php实现静态

php实现静态

静态化实现方法 PHP实现静态化主要通过生成HTML文件或缓存机制来减少服务器动态解析的开销。以下是几种常见方法: 生成静态HTML文件 通过file_put_contents()将动态内容保存为H…