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 ...
随机推荐
- python之爬虫_并发(串行、多线程、多进程、异步IO)
并发 在编写爬虫时,性能的消耗主要在IO请求中,当单进程单线程模式下请求URL时必然会引起等待,从而使得请求整体变慢 import requests def fetch_async(url): res ...
- js中模拟a标签的点击事件
var a = document.createElement('a'); a.target = "_blank"; a.href = "personal"; a ...
- json转对象
1,引入依赖 <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib& ...
- 实验一linux 系统简介和实验二基本概念及操作
作业 zy e
- IIs8 svc
IIS8中添加WCF支持几种方法小结[图文] 方法一 最近在做Silverlight,Windows Phone应用移植到Windows 8平台,在IIS8中测试一些传统WCF服务应用,发现IIS8不 ...
- Codeforces Round #341 (Div. 2) E. Wet Shark and Blocks dp+矩阵加速
题目链接: http://codeforces.com/problemset/problem/621/E E. Wet Shark and Blocks time limit per test2 se ...
- 校园跳蚤市场-Sprint计划
一.现状 小组成员初步了解所做项目的大致内容,需要时间一步一步分析和规划. 二.部分需求索引卡 第一个阶段完成项目的其中一个模块(商品信息模块). 三.任务认领 产品负责人:林海信 Master:何武 ...
- thinkphp学习3-模板与视图
1.模板赋值 如果要在模板中输出变量,必须在在控制器中把变量传递给模板,系统提供了assign方法对模板变量赋值,无论何种变量类型都统一使用assign赋值. $this->assign('na ...
- SQL语句中 chinese_prc_CS_AI_WS 以及replace用法
Select * from [DBData].[dbo].[T_Student] where Name='lilei' 查询结果如下: 结论:由查询结果可知 SQL Server ...
- 014 C语言文法定义与C程序的推导过程