前言

最近一直在忙(2月份沉迷steam,3月开始工作各种忙),好久没更新博客了,不过也积累了一些,忙里偷闲记录一下。

这个需求是这样的,我之前做了个工单系统,现在要对登录、注册、发起工单这些功能做限流,不能让用户请求太频繁。

从 .Net7 开始,已经有内置的限流功能了,但目前我们的项目还在使用 .Net6 LTS 版本,下一个 LTS 没发布之前,暂时不考虑使用 .Net7 这种非 LTS 版本。

然后我找到了这个 AspNetCoreRateLimit 组件,在 Github 上有接近三千个星星,看了一下文档使用也简单灵活,于是决定尝试一下~

AspNetCoreRateLimit 组件

项目主页: https://github.com/stefanprodan/AspNetCoreRateLimit

这是官方的介绍:

AspNetCoreRateLimit is an ASP.NET Core rate limiting solution designed to control the rate of requests that clients can make to a Web API or MVC app based on IP address or client ID.

The AspNetCoreRateLimit NuGet package contains an IpRateLimitMiddleware and a ClientRateLimitMiddleware, with each middleware you can set multiple limits for different scenarios like allowing an IP or Client to make a maximum number of calls in a time interval like per second, 15 minutes, etc. You can define these limits to address all requests made to an API or you can scope the limits to each API URL or HTTP verb and path.

用最近很厉害的 ChatGPT 翻译一下:

AspNetCoreRateLimit是一个ASP.NET Core速率限制解决方案,旨在基于IP地址或客户端ID控制客户端对Web API或MVC应用程序发出请求的速率。

AspNetCoreRateLimit NuGet包 包含一个IpRateLimitMiddleware和一个ClientRateLimitMiddleware,每个中间件都可以为不同的场景设置多个限制,比如允许IP或客户端在时间间隔内进行最大数量的调用,比如每秒、15分钟等。您可以定义这些限制以处理对API发出的所有请求,也可以将限制范围限定为每个API URL或HTTP动词和路径。

这个组件使用起来挺灵活的,直接在 AspNetCore配置 里定义规则,意味着可以不重新编译程序就修改限流规则,官方给的例子是直接在 appsettings.json 里配置,但使用其他配置源理论上也没问题(配置中心用起来)。

简单介绍下这个组件的思路

首先它有两种模式:

  • 根据IP地址限流
  • 根据 ClientID 限流

IP地址很容易理解,ClientID 我一开始以为是用户ID,不过看了说明,是一个放在请求头里的参数,比如 X-ClientId,这个要自己实现,可以直接用用户ID。

为了方便使用,我这个项目里面直接用IP地址模式。

RateLimit 组件可以配置全局的限流,也可以配置对某个IP地址(段)进行限流。

配置服务

为了从 appsettings.json 读取数据,先在 Program.cs 注册配置服务

builder.Services.AddOptions();

然后写个扩展方法来注册 RateLimit 的相关服务

引入命名空间

using AspNetCoreRateLimit;
using AspNetCoreRateLimit.Redis;
using StackExchange.Redis;

写个静态类

public static class ConfigureRateLimit {
public static void AddRateLimit(this IServiceCollection services, IConfiguration conf) {
//load general configuration from appsettings.json
services.Configure<IpRateLimitOptions>(conf.GetSection("IpRateLimiting")); var redisOptions = ConfigurationOptions.Parse(conf.GetConnectionString("Redis"));
services.AddSingleton<IConnectionMultiplexer>(provider => ConnectionMultiplexer.Connect(redisOptions));
services.AddRedisRateLimiting(); services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
} public static IApplicationBuilder UseRateLimit(this IApplicationBuilder app) {
app.UseIpRateLimiting(); return app;
}
}

来解析一下配置的代码。

我暂时不需要对不同的IP地址段应用不同的限流规则

所以直接用 IpRateLimitOptions

services.Configure<IpRateLimitOptions>(conf.GetSection("IpRateLimiting"));

要做根据IP限流,就得记录每个IP访问了多少次,RateLimit 组件支持多种存储方式,最简单的可以直接存内存里,不过为了稳定我还是选择 Redis。

这几行代码就是配置 Redis 的。

var redisOptions = ConfigurationOptions.Parse(conf.GetConnectionString("Redis"));
services.AddSingleton<IConnectionMultiplexer>(provider => ConnectionMultiplexer.Connect(redisOptions));
services.AddRedisRateLimiting();

最后注入一下 IRateLimitConfiguration,我猜应该是中间件要用到的。至少我目前在 Controller 代码里不需要用到任何跟 RateLimit 有关的代码。

写完了扩展方法,回到 Program.cs

注册服务

builder.Services.AddRateLimit(builder.Configuration);

添加中间件

var app = builder.Build();

app.UseExceptionless();
app.UseStaticFiles(new StaticFileOptions {
ServeUnknownFileTypes = true
});
app.UseRateLimit(); // ... app.Run();

我这里把 UseRateLimit 放在 UseStaticFiles 后面,不然页面里的静态文件都被算进去访问次数,很快就被限流了。

配置

appsettings.json 里写具体的限流规则。

官网提供的配置规则不能照抄,要理解一下他的文档

  • EnableEndpointRateLimiting - 这个选项要设置为 true ,不然设置的限流是全局的,不能根据某个路径单独设置限流
  • StackBlockedRequests - 按照默认的设置为 false 就行,设置成 true 的话,一个接口被限流之后再重复请求还会计算到访问次数里面,这样有可能导致限流到天荒地老。

其他的配置顾名思义,懂的都懂。

GeneralRules 是对具体路径的限流规则

如果全局限流,把 EnableEndpointRateLimiting 设置为 false 的话,那就这样设置,1分钟只能访问5次

{
"Endpoint": "*",
"Period": "1m",
"Limit": 5
}

Endpoint 可以设置 HTTP方法:路径 的形式,比如 post:/account/login 具体看文档吧(参考文档第三条)

附上我的配置文件,对添加工单、登录、注册接口进行限流。

{
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"RealIpHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"IpWhitelist": [],
"EndpointWhitelist": [
"get:/api/license",
"*:/api/status"
],
"ClientWhitelist": [
"dev-id-1",
"dev-id-2"
],
"GeneralRules": [
{
"Endpoint": "*:/ticket/add",
"Period": "1m",
"Limit": 5
},
{
"Endpoint": "post:/account/login",
"Period": "1m",
"Limit": 5
},
{
"Endpoint": "post:/account/SignUp",
"Period": "1m",
"Limit": 5
}
],
"QuotaExceededResponse": {
"Content": "{{ \"message\": \"先别急,你访问得太快了!\", \"details\": \"已经触发限流。限流规则: 每 {1} 只能访问 {0} 次。请 {2} 秒后再重试。\" }}",
"ContentType": "application/json",
"StatusCode": 429
}
}
}

同时自定义了被限流时的提示。

效果如下

{
"message": "先别急,你访问得太快了!",
"details": "已经触发限流。限流规则: 每 1m 只能访问 5 次。请 16 秒后再重试。"
}

参考资料

Asp-Net-Core开发笔记:使用RateLimit中间件实现接口限流的更多相关文章

  1. ASP.NET Core 开发-中间件(Middleware)

    ASP.NET Core开发,开发并使用中间件(Middleware). 中间件是被组装成一个应用程序管道来处理请求和响应的软件组件. 每个组件选择是否传递给管道中的下一个组件的请求,并能之前和下一组 ...

  2. ASP.NET Core 开发-中间件(StaticFiles)使用

    ASP.NET Core 开发,中间件(StaticFiles)的使用,我们开发一款简易的静态文件服务器. 告别需要使用文件,又需要安装一个web服务器.现在随时随地打开程序即可使用,跨平台,方便快捷 ...

  3. 在CentOS7 开发与部署 asp.net core app笔记

    原文:在CentOS7 开发与部署 asp.net core app笔记 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/lihongzhai/art ...

  4. [ASP.NET Core开发实战]基础篇03 中间件

    什么是中间件 中间件是一种装配到应用管道,以处理请求和响应的组件.每个中间件: 选择是否将请求传递到管道中的下一个中间件. 可在管道中的下一个中间件前后执行. ASP.NET Core请求管道包含一系 ...

  5. ASP.Net Core开发(踩坑)指南

    ASP.NET与ASP.NET Core很类似,但它们之间存在一些细微区别以及ASP.NET Core中新增特性的使用方法,在此之前也写过一篇简单的对比文章ASP.NET MVC应用迁移到ASP.NE ...

  6. C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式

    C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...

  7. asp.net core开发注意事项

    1.类库的创建尽量选择.net standard. 如果选择.net core 则.net framework不能调用该类库, .net core和.net framework都可以调用.net st ...

  8. ASP.NET Core 开发人员异常页面

    UseDeveloperExceptionPage 中间件 我们谈谈在 Startup 类的 Configure()方法中以下代码: public void Configure(IApplicatio ...

  9. 2月送书福利:ASP.NET Core开发实战

    大家都知道我有一个公众号“恰童鞋骚年”,在公众号2020年第一天发布的推文<2020年,请让我重新介绍我自己>中,我曾说到我会在2020年中每个月为所有关注“恰童鞋骚年”公众号的童鞋们送一 ...

  10. [ASP.NET Core开发实战]开篇词

    前言 本系列课程文章主要是学习官方文档,再输出自己学习心得,希望对你有所帮助. 课程大纲 本系列课程主要分为三个部分:基础篇.实战篇和部署篇. 希望通过本系列课程,能让大家初步掌握使用ASP.NET ...

随机推荐

  1. HDK_节点开发:SOP_ComputeVisibility

    Houdini版本:18.5.596 节点概述:剔除模型在某视线方向下所有不可见面. 参数界面: 输入:三角化的模型(左),可选输入遮挡模型(右) 原理:在画布上绘制该方向上的最近深度,作为判定各面可 ...

  2. 兼容url传参

    //兼容url传参            if(java.nio.charset.Charset.forName("ISO-8859-1").newEncoder().canEnc ...

  3. 2020年第11届蓝桥杯C/C++B组 第一轮省赛

    # JJU-干干 试题 A: 跑步训练 代码: #include <stdio.h> #include <stdlib.h> /* run this program using ...

  4. 在Scorpio 1.0(天蝎座)中使用C# System.Diagnostics.Process打开chrome遇到的问题

    1 //在天蝎座 中使用C# System.Diagnostics.Process打开chrome遇到的问题 2 DiagProcess = import_type("System.Diag ...

  5. 1903021126-申文骏-Java第十一周作业-Java中继承、多态及抽象类的使用

    项目 内容 课程班级博客链接 19级信计班(本) 作业要求链接 第十一周作业 博客名称 1903021126-申文骏-Java第十一周作业-Java中继承.多态及抽象类的使用 作业要求 每道题要有题目 ...

  6. find_in_set使用:匹配按逗号分隔后的内容

    SELECT  * FROM `tb_test` WHERE c_id ='123' AND create_time LIKE '2021-06-03%'  AND find_in_set('A362 ...

  7. MyBatis Generator使用方法

    第一步:在resources文件夹下创建一个目录mybatis-generator,在目录mybatis-generator下创建文件generatorConfig.xml(此处的目录名可任意取) 第 ...

  8. div隐藏、显示

    JS隐藏和显示div的方式有两种: 需要注意的是用JS设置div的属性,必须在ccs中设置对应属性,否则报错. 同理可以设置相同class,进行批量设置. display--隐藏后释放占用的页面空间. ...

  9. 基于mysql纯java的智能题库(后期填写注释)

    1 package controller; 2 3 import admin.entity.Admin; 4 import admin.service.AdminService; 5 import a ...

  10. [api自动化]快速导出接口到jmeter脚本

    [场景]在项目做接口自动化的时候,大家一般找接口文档或者其他接口资料,逐一编写脚本.这样效率低,且容易由于文档未更新导致接口调试不通 [解决方案]页面上操作对应功能,直接捕获用到的接口,导出到jmet ...