fiberphp/limiter

There is no license information available for the latest version (dev-master) of this package.

🚦 FiberPHP 限流器 —— Redis Hash 固定窗口计数,支持 IP 白名单(单 IP、CIDR、通配符),协程安全。

Maintainers

Package info

gitee.com/FiberPHP/limiter

Issues

pkg:composer/fiberphp/limiter

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

dev-master 2026-08-24 11:29 UTC

This package is auto-updated.

Last update: 2026-08-24 11:36:28 UTC


README

基于 Redis 的限流器组件,适用于 FiberPHP 框架。采用固定窗口算法,通过 Redis Hash 分桶计数,热路径仅需一次 HINCRBY 调用,性能开销极低。内置 IP 白名单机制(支持单 IP、CIDR、通配符三种匹配方式)。

特性

  • 固定窗口限流算法,窗口按 TTL 对齐到 epoch
  • Redis Hash 按天分桶存储,热路径仅一次 HINCRBY,过期时间通过 Lua 脚本惰性延长(只增不减)
  • IP 白名单支持单 IP、CIDR(如 192.168.0.0/16)、通配符(如 192.168.*.*)三种格式
  • 提供 attempt()(返回布尔值)与 check()(超限自动抛异常)两种调用方式
  • 异常类与 HTTP 状态码可配置,默认返回 429 Too Many Requests
  • 懒初始化:首次调用自动初始化,无需 ServiceProvider

安装

在项目根目录的 composer.json 中添加仓库与依赖:

{
    "require": {
        "fiberphp/limiter": "*"
    },
    "repositories": [
        {
            "type": "path",
            "url": "path/to/haohai/*",
            "options": { "symlink": true, "relative": false }
        }
    ]
}

执行安装:

composer require fiberphp/limiter

安装完成后,配置文件会被发布到项目的 config/limiter/app.php

配置说明

配置文件位于 config/limiter/app.php,通过 config('limiter.app.xxx') 访问。

配置项类型默认值说明
enablebooltrue是否启用限流器
ip_whitelistarray[]不受频率限制的 IP 列表,支持单 IP、CIDR、通配符
exceptionstringLimitException::class超出限流时抛出的异常类,需继承 BusinessException

配置示例:

<?php
use FiberPHP\Limiter\LimitException;

return [
    'enable' => true,
    // 这些 ip 的请求不做频率限制
    'ip_whitelist' => [
        '127.0.0.1',          // 单 IP
        '10.0.0.0/8',         // CIDR
        '192.168.*.*',        // 通配符
    ],
    'exception' => LimitException::class,
];

注意:组件通过 FiberPHP\Redis\Sync 客户端连接 Redis,连接名为 limiter,需在 Redis 组件(fiberphp/redis)的配置中预先定义名为 limiter 的连接。

使用方法

1. 超限自动抛异常

check() 会在超出限制时自动抛出配置中指定的异常,适合在中间件或控制器入口直接调用:

use FiberPHP\Limiter\Limiter;

// 每个 IP 每分钟(60 秒)最多 100 次请求,超限抛出 LimitException(HTTP 429)
$ip = $request->getRealIp();
Limiter::check('ip:' . $ip, 100, 60, '请求过于频繁,请稍后再试');

2. 手动判断是否超限

attempt() 返回布尔值,由调用方自行决定后续逻辑:

use FiberPHP\Limiter\Limiter;
use FiberPHP\Limiter\LimitException;

// 同一用户每秒最多调用 5 次发短信接口
$key = 'sms:' . $userId;
if (!Limiter::attempt($key, 5, 1)) {
    throw new LimitException('操作过于频繁', 429);
}
// 继续业务逻辑

3. 结合 IP 白名单

在限流前先判断 IP 是否在白名单,白名单内的请求直接放行:

use FiberPHP\Limiter\Limiter;

$ip = $request->getRealIp();

if (!Limiter::isIpWhiteListed($ip)) {
    Limiter::check('ip:' . $ip, 100, 60, '请求过于频繁,请稍后再试');
}

// 处理请求

限流算法说明

组件采用固定窗口算法(Fixed Window)

  1. 窗口对齐:窗口结束时间按 TTL 对齐到 epoch(Unix 时间戳原点)。例如 TTL 为 60 秒时,窗口边界为每分钟的整点(00:0001:0002:00 ...),所有落在同一窗口内的请求共享同一计数。
  2. 按天分桶:Redis 端以本地日期(Y-m-d)为单位,每天使用一个 Hash(limiter-YYYY-MM-DD),字段格式为 {key}-{窗口结束时间}-{ttl},值为该窗口内的累计请求数。
  3. 热路径优化:计数仅执行一次 HINCRBY。过期时间的延长通过 Lua 脚本惰性触发,且只在本地缓存认为需要延长时才调用,脚本保证过期时间只增不减。
  4. 自动回收:Hash 的过期时间覆盖当天最后一个窗口的结束时刻,过期后由 Redis 自动清理;本地进程内的过期时间缓存每 60 秒清理一次。

相比滑动窗口,固定窗口实现简单、性能更高,但在窗口边界处可能出现瞬时双倍流量(相邻两个窗口各放过 limit 次)。如对边界突刺敏感,可结合业务适当调小 limit 或缩短 ttl

IP 白名单机制

isIpWhiteListed() 依次匹配 ip_whitelist 配置中的每一项,命中任意一条即返回 true。匹配规则由 ipInRange() 实现,支持三种格式:

格式示例说明
单 IP127.0.0.1完全相等的 IPv4 地址
CIDR192.168.0.0/16通过子网掩码按位匹配网段
通配符192.168.*.** 匹配任意一段(一位或多位数字)

匹配仅针对 IPv4。白名单在首次调用时一次性懒加载到进程内存,运行期直接读取内存,无额外开销。

异常处理

超限时默认抛出 FiberPHP\Limiter\LimitException,它继承自 FiberPHP\Exception\BusinessException,HTTP 状态码为 429

namespace FiberPHP\Limiter;

use FiberPHP\exception\BusinessException;

class LimitException extends BusinessException
{
    protected int $httpCode = 429;
}

可通过 exception 配置项替换为自定义异常类(需继承 BusinessException 并能被 (string) 实例化构造)。调用 check() 时传入的 message 会作为异常消息:

Limiter::check($key, 100, 60, '自定义提示信息');

若不希望抛异常,改用 attempt() 自行处理:

if (!Limiter::attempt($key, 100, 60)) {
    // 自定义响应
    return json(['code' => 429, 'msg' => 'Too Many Requests'])->withStatus(429);
}

目录结构

fiberphp/limiter/
├── src/
│   ├── config/
│   │   └── app.php          # 默认配置,安装时发布到 config/limiter/app.php
│   ├── Install.php          # 安装钩子,定义配置路径
│   ├── LimitException.php   # 限流异常,HTTP 429
│   ├── Limiter.php          # 限流器核心,提供 attempt/check/白名单能力
│   └── Redis.php            # Redis 存储实现,固定窗口计数与过期管理
├── composer.json
└── README.md

依赖说明

依赖说明
PHP >= 8.2运行环境要求
fiberphp/http提供 HTTP 请求与异常处理基础
fiberphp/redis提供 FiberPHP\Redis\Sync 同步 Redis 客户端,需配置名为 limiter 的连接
fiberphp/framework (dev)开发依赖,提供框架运行环境与 InstallHelper

命名空间为 FiberPHP\Limiter\(PSR-4,对应 src/ 目录)。