写点什么

hyperf-throttle-requests,一个超牛的 PHP 限流神器

作者:左诗右码
  • 2024-11-30
    上海
  • 本文字数:4457 字

    阅读完需:约 15 分钟

hyperf-throttle-requests,一个超牛的 PHP 限流神器

在分布式系统和微服务架构中,API 的稳定性和可用性至关重要。为了保护后端服务不受恶意攻击和流量高峰的影响,请求频率限制(Rate Limiting)成为了一种常见的策略。


Hyperf 框架作为一款高性能的 PHP 框架,提供了丰富的组件来支持各种场景。


今天,我们要介绍的是 hyperf-throttle-requests 库,一个专为 Hyperf 框架设计的请求频率限流器。

hyperf-throttle-requests 库简介

hyperf-throttle-requests 是一个功能类似于 Laravel 框架中 throttle 中间件的组件。它能够限制用户在一定时间内的请求次数,超过限制则拒绝服务,从而保护后端服务不受恶意请求或高并发流量的冲击。


最新版的 hyperf-throttle-requests 包,已经支持 hyperf 3.1 版本

安装

要在你的 Hyperf 项目中使用 hyperf-throttle-requests,首先需要通过 Composer 安装:


composer require pudongping/hyperf-throttle-requests:^3.0 -vvv
复制代码


确保你的环境满足以下要求:


  • PHP 版本 >= 8.1

  • Hyperf 框架版本 ~3.1.0

配置

安装完成后,需要发布配置文件以进行个性化设置:


php bin/hyperf.php vendor:publish pudongping/hyperf-throttle-requests
复制代码


这将在 config/autoload 目录下生成 hyperf-throttle-requests.php 配置文件。你可以在此文件中设置限流器的各种参数,如存储驱动、最大请求次数、时间窗口等。

配置说明

使用

该组件提供了以下 3 种调用方式:

第一种:使用注解 Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests

该组件提供 Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests 注解,作用于类、类方法。


配置作用优先级为:类方法上的注解配置 > 类上的注解配置 > config/autoload/hyperf-throttle-requests.php > 注解默认配置


注意:只有使用注解调用时,才会使用 config/autoload/hyperf-throttle-requests.php 配置文件中的配置项。

使用注解 Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests 作用于类上,示例:


<?php/** * * * Created by PhpStorm * User: Alex * Date: 2023-06-21 11:36 */declare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;use Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests;
#[AutoController(prefix: "throttle-requests")]#[ThrottleRequests]class ThrottleRequestsController{
public function t1() { return [ 'name' => 'alex' ]; }
public function t2() { return [ 'name' => 'harry' ]; }
}
复制代码


当提供 key 参数,且 key 参数的值为一个标量(不会变化的值)时,则该限流器同时作用于含有等值 key 上。举个例子来说:在以下代码中Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests 注解作用于类上,也就意味着当访问 /throttle-requests/t1 路由和 /throttle-requests/t2 路由时,共享相同的配置信息,由于此时的 key 参数的值为一个标量,也就意味着此时的现象是:在 15 秒内,当访问/throttle-requests/t1 路由和 /throttle-requests/t2 路由时,总共只允许访问 5 次。



<?phpdeclare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;use Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests;
#[AutoController(prefix: "throttle-requests")]#[ThrottleRequests(key: "test-throttle", maxAttempts: 5, decaySeconds: 15, prefix: "TR:")]class ThrottleRequestsController{
public function t1() { return [ 'name' => 'alex' ]; }
public function t2() { return [ 'name' => 'harry' ]; }
}
复制代码

使用注解 Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests 作用于类方法上,示例:

以下示例代码和以上示例代码,均为同样的效果。



<?phpdeclare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;use Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests;
#[AutoController(prefix: "throttle-requests")]class ThrottleRequestsController{
#[ThrottleRequests(key: "test-throttle", maxAttempts: 5, decaySeconds: 15, prefix: "TR:")] public function t1() { return [ 'name' => 'alex' ]; }
#[ThrottleRequests(key: "test-throttle", maxAttempts: 5, decaySeconds: 15, prefix: "TR:")] public function t2() { return [ 'name' => 'harry' ]; }
}
复制代码

第二种:使用 throttle_requests(string $rateLimits = '30,60', string $prefix = '', string $key = '', mixed $generateKeyCallable = [], mixed $tooManyAttemptsCallback = []) 助手函数


<?phpdeclare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;
#[AutoController(prefix: "throttle-requests")]class ThrottleRequestsController{
public function t1() { throttle_requests(rateLimits: "5,15"); return [ 'name' => 'alex' ]; }
}
复制代码

第三种:直接调用 Pudongping\HyperfThrottleRequests\Handler\ThrottleRequestsHandler@handle() 方法


<?phpdeclare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;use Pudongping\HyperfThrottleRequests\Handler\ThrottleRequestsHandler;use Hyperf\Context\ApplicationContext;
#[AutoController(prefix: "throttle-requests")]class ThrottleRequestsController{
public function t2() { ApplicationContext::getContainer()->get(ThrottleRequestsHandler::class)->handle(5, 15); return [ 'name' => 'harry' ]; }
}
复制代码

关于计数器的 key

本质上,当传入的 key 参数不为空字符串时,则以传入的 key 为主。当 key 为空字符串,但是 generateKeyCallable 为一个可调用的回调函数时,则以回调函数的返回值作为计数器的 key。否则默认为 sha1(当前路由地址路径 . '|' . 当前客户端 IP 地址) 作为 key。


其实质来说,generateKeyCallable 回调函数就是去生成 key 参数的值,这是为了方便使用者根据自己的需求动态的去生成计数器的键名。比如说:可能当用户登录之后,会加上 user_id 作为计数器的 key。


使用自定义 key 示例:


App\Controller\ThrottleRequestsController.php 文件中



<?phpdeclare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;use Pudongping\HyperfThrottleRequests\Handler\ThrottleRequestsHandler;use Hyperf\Context\ApplicationContext;use Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests;use App\Helper\ThrottleRequestsHelper;use Hyperf\HttpServer\Contract\RequestInterface;
#[AutoController(prefix: "throttle-requests")]class ThrottleRequestsController{
public function __construct(protected RequestInterface $request) {
}
#[ThrottleRequests(generateKeyCallable: [ThrottleRequestsHelper::class, "generateKeyCallable"])] public function t1() { return [ 'name' => 'alex' ]; }
public function t2() { ApplicationContext::getContainer() ->get(ThrottleRequestsHandler::class) ->handle( 5, 15, generateKeyCallable: [$this, 'generateKeyCallable'] );
return [ 'name' => 'harry' ]; }
public function generateKeyCallable() { return 'alex_' . $this->request->url(); }
}
复制代码

触发访问频率限制

当限流被触发时,默认会抛出 Pudongping\HyperfThrottleRequests\Exception\ThrottleRequestsException 异常,可以通过捕获异常或者配置 tooManyAttemptsCallback 限流回调处理。例如:


App\Controller\ThrottleRequestsController.php 文件中



<?phpdeclare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;use Pudongping\HyperfThrottleRequests\Handler\ThrottleRequestsHandler;use Hyperf\Context\ApplicationContext;use Pudongping\HyperfThrottleRequests\Annotation\ThrottleRequests;use App\Helper\ThrottleRequestsHelper;
#[AutoController(prefix: "throttle-requests")]class ThrottleRequestsController{
#[ThrottleRequests(tooManyAttemptsCallback: [ThrottleRequestsHelper::class, 'tooManyAttemptsCallback'])] public function t1() { return [ 'name' => 'alex' ]; }
public function t2() { ApplicationContext::getContainer() ->get(ThrottleRequestsHandler::class) ->handle( 5, 15, tooManyAttemptsCallback: function () { var_dump('请求过于频繁'); throw new \RuntimeException('请求过于频繁', 429); } );
return [ 'name' => 'harry' ]; }
}
复制代码


App\Helper\ThrottleRequestsHelper.php 文件中



<?phpdeclare(strict_types=1);
namespace App\Helper;
use Hyperf\HttpServer\Contract\RequestInterface;use Hyperf\Context\ApplicationContext;
class ThrottleRequestsHelper{
public function __construct(protected RequestInterface $request) {
}
public static function generateKeyCallable() { $request = ApplicationContext::getContainer()->get(RequestInterface::class); return $request->getUri()->getPath(); }
public static function tooManyAttemptsCallback() { var_dump('Too Many Attempts.'); throw new \RuntimeException('请求过于频繁', 429); }
}
复制代码

结语

hyperf-throttle-requests 库为 Hyperf 框架的开发者提供了一个强大的请求频率限流工具,帮助他们保护后端服务不受恶意请求的影响。


希望本文能够帮助你了解并开始使用 hyperf-throttle-requests,为你的项目增加一层安全保障。

发布于: 刚刚阅读数: 4
用户头像

左诗右码

关注

全网同名,欢迎关注交流。 2018-11-22 加入

三观比五官更正,思想比套路更深。常用技术栈PHP、Go、Python,享受编程,平时爱好写点文章。V公主号:「左诗右码」,欢迎关注交流。

评论

发布
暂无评论
hyperf-throttle-requests,一个超牛的 PHP 限流神器_左诗右码_InfoQ写作社区