Laravel 限流中间件 throttle 简析
1. 在Laravel 中配置
在 app\Http\Kernel.php 中,默认添加到中间件组 api 下,1分钟60次。
2. 限流原理
- 获取唯一请求来源,进行唯一标识(key)
- 获取该请求请求次数 (hits)
- 判断是否超过最大限制
- 若达到上限,进入5。未达到,则进入6
- 丢出访问次数限制异常,结束请求。
- 首先判断hits 是否达到限制,若未达到,进入7。若达到,进入8。
- hits 进行计数 + 1,更新到缓存中。 若是第一次,则需要 hits = 1(次数), 并添加访问标识 key (1分钟)到缓存中,以标记请求周期。
- 请求次数已达到上限(hits >= 60),此时需要判断是否在周期范围内(1分钟),若在周期内,进入9;不在周期内,进入10.
- 此时请求处在 “1分钟内请求次数达到60次”,即达到限制,返回 false 。
- 此时请求处在 “不在1分钟内请求次数达到60次”,即不在周期内,需要重新计算周期。
3. 代码实现
3.1 业务逻辑在 ThrottleRequests -> handle 中实现。
public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1)
{
// 获取唯一请求来源 2.1
$key = $this->resolveRequestSignature($request);
// 获取实际请求次数 2.2
$maxAttempts = $this->resolveMaxAttempts($request, $maxAttempts);
// 判断是否达到上限 2.3
if ($this->limiter->tooManyAttempts($key, $maxAttempts)) {
// 禁止请求 2.5
throw $this->buildException($key, $maxAttempts);
}
// 2.7 计数
$this->limiter->hit($key, $decayMinutes); $response = $next($request); return $this->addHeaders(
$response, $maxAttempts,
$this->calculateRemainingAttempts($key, $maxAttempts)
);
}
3.2 限流方法 在 Illuminate\Cache\RateLimiter 中
<?php namespace Illuminate\Cache; use Illuminate\Support\InteractsWithTime;
use Illuminate\Contracts\Cache\Repository as Cache; class RateLimiter
{
use InteractsWithTime; /**
* The cache store implementation.
*
* @var \Illuminate\Contracts\Cache\Repository
*/
protected $cache; /**
* Create a new rate limiter instance.
*
* @param \Illuminate\Contracts\Cache\Repository $cache
* @return void
*/ // 初始化缓存
public function __construct(Cache $cache)
{
$this->cache = $cache;
} /**
* Determine if the given key has been "accessed" too many times.
*
* @param string $key
* @param int $maxAttempts
* @return bool
*/ // 判断是否达到上限
public function tooManyAttempts($key, $maxAttempts)
{
// 判断次数,是否达到限制(60次)
if ($this->attempts($key) >= $maxAttempts) {
// 判断是否在限制周期内(1分钟内)
if ($this->cache->has($key.':timer')) {
return true;
}
// 2.10 重新计算周期
$this->resetAttempts($key);
} return false;
} /**
* Increment the counter for a given key for a given decay time.
*
* @param string $key
* @param float|int $decayMinutes
* @return int
*/
public function hit($key, $decayMinutes = 1)
{
// 对应2.7 ,添加周期缓存
$this->cache->add(
$key.':timer', $this->availableAt($decayMinutes * 60), $decayMinutes
);
// 对应2.7 ,添加请求次数缓存
$added = $this->cache->add($key, 0, $decayMinutes);
// 请求次数 + 1
$hits = (int) $this->cache->increment($key);
// 更新次数
if (! $added && $hits == 1) {
$this->cache->put($key, 1, $decayMinutes);
}
// 返回次数
return $hits;
} /**
* Get the number of attempts for the given key.
*
* @param string $key
* @return mixed
*/ // 获取请求次数,默认0
public function attempts($key)
{
return $this->cache->get($key, 0);
} /**
* Reset the number of attempts for the given key.
*
* @param string $key
* @return mixed
*/ // 重置请求周期
public function resetAttempts($key)
{
return $this->cache->forget($key);
} /**
* Get the number of retries left for the given key.
*
* @param string $key
* @param int $maxAttempts
* @return int
*/ // 获取剩余次数
public function retriesLeft($key, $maxAttempts)
{
$attempts = $this->attempts($key); return $maxAttempts - $attempts;
} /**
* Clear the hits and lockout timer for the given key.
*
* @param string $key
* @return void
*/ // 清除请求计数和周期
public function clear($key)
{
$this->resetAttempts($key); $this->cache->forget($key.':timer');
} /**
* Get the number of seconds until the "key" is accessible again.
*
* @param string $key
* @return int
*/ // 判断是否在周期内
public function availableIn($key)
{
return $this->cache->get($key.':timer') - $this->currentTime();
}
}
PS: ThrottleRequestsWithRedis 和 ThrottleRequests 是相同的,区别在于前者指定 Redis 作为缓存,后者无限制(使用Laravel配置缓存)
Laravel 限流中间件 throttle 简析的更多相关文章
- Asp.Net Core 7 preview 4 重磅新特性--限流中间件
前言 限流是应对流量暴增或某些用户恶意攻击等场景的重要手段之一,然而微软官方从未支持这一重要特性,AspNetCoreRateLimit这一第三方库限流库一般作为首选使用,然而其配置参数过于繁多,对使 ...
- 从-99打造Sentinel高可用集群限流中间件
接上篇Sentinel集群限流探索,上次简单提到了集群限流的原理,然后用官方给的 demo 简单修改了一下,可以正常运行生效. 这一次需要更进一步,基于 Sentinel 实现内嵌式集群限流的高可用方 ...
- ASP.NET Core WebApi AspNetCoreRateLimit 限流中间件学习
AspNetCoreRateLimit介绍: AspNetCoreRateLimit是ASP.NET核心速率限制框架,能够对WebApi,Mvc中控制限流,AspNetCoreRateLimit包包含 ...
- AspNetCore 限流中间件IpRateLimitMiddleware 介绍
IpRateLimitMiddleware(Github: AspNetCoreRateLimit) 是ASPNETCore的一个限流的中间件,用于控制客户端调用API的频次, 如果客户端频繁访问服务 ...
- .NET服务治理之限流中间件-FireflySoft.RateLimit
概述 FireflySoft.RateLimit自2021年1月发布第一个版本以来,经历了多次升级迭代,目前已经十分稳定,被很多开发者应用到了生产系统中,最新发布的版本是3.0.0. Github:h ...
- 【.NET Core项目实战-统一认证平台】第七章 网关篇-自定义客户端限流
[.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章我介绍了如何在网关上增加自定义客户端授权功能,从设计到编码实现,一步一步详细讲解,相信大家也掌握了自定义中间件的开发技巧了,本篇我们 ...
- 漏桶、令牌桶限流的Go语言实现
限流 限流又称为流量控制(流控),通常是指限制到达系统的并发请求数. 我们生活中也会经常遇到限流的场景,比如:某景区限制每日进入景区的游客数量为8万人:沙河地铁站早高峰通过站外排队逐一放行的方式限制同 ...
- AspNetCore添加API限流
最近发现有客户在大量的请求我们的接口,出于性能考虑遂添加了请求频率限制. 由于我们接口请求的是.Net Core写的API网关,所以可以直接添加一个中间件,中间件中使用请求的地址当key,通过配置中心 ...
- 【Dnc.Api.Throttle】适用于.Net Core WebApi接口限流框架
Dnc.Api.Throttle 适用于Dot Net Core的WebApi接口限流框架 使用Dnc.Api.Throttle可以使您轻松实现WebApi接口的限流管理.Dnc.Api.Thr ...
随机推荐
- Scrum立会报告+燃尽图(Final阶段第五次)
此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2484 项目地址:https://coding.net/u/wuyy694 ...
- 结对作业(1.0版)(bug1已修复)
import java.awt.EventQueue; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing ...
- 如何在mvc项目中使用apiController
文章地址:How do you route from an MVC project to an MVC ApiController in another project? 文章地址:How to Us ...
- 巧妙使用CSS媒体查询(Media Queries)和JavaScript判断浏览器设备类型的好方法
有无数的理由要求我们在任何时候都应该知道用户是使用的什么设备浏览我们的网站——宽屏,普通屏,平板,手机?知道这些特征,我们web应用的CSS和JavaScript才能同步做相应的操作.在给Mozill ...
- [转帖]华为Hi 1620 等ARM 服务器版本CPU信息.
华为ARM服务器恐依赖党政输血续命 一旦制裁立马休克 http://www.sohu.com/a/240833070_99934330 几年前,ARM服务器被业界炒的火热,AMD.高通.Marvell ...
- Navicat for MySQL和Navicat Premium之间的区别
首先两款软件都可以用来管理数据库链接MySQL和MariaDB 相对于新手或者前端工程师使用Navicat for MySQL就够了,功能相对于Navicat Premium比较少Navicat fo ...
- Vue 小组件input keyup.enter绑定
<div id="todo-list-example"> <input v-model="newTodoText" v-on:keyup.en ...
- Java-JDBC.mysql 工具类 读取本地文件配置
引用 mysql-connector-jav 的jar 配置文件为 database.propertties . 格式如下 driverClass=com.mysql.jdbc.Driver ur ...
- 深入理解JAVA虚拟机阅读笔记6——线程安全与锁优化
线程安全:如果一个对象可以安全的被多个线程同时使用,那它就是线程安全的. 一.Java中的线程安全 1.不可变 不可变的对象一定是线程安全的.String.枚举类型.java.lang.Number的 ...
- Netty简单使用
目录 丢弃服务器 DiscardServerHandler DiscardServer 测试 应答服务器 时间服务器 TimeServerHandler TimeClient TimeClientHa ...