Asp.NET Core 限流控制-AspNetCoreRateLimit

共 8656字,需浏览 18分钟

 ·

2021-03-05 18:56

起因:

 近期项目中,提供了一些调用频率较高的api接口,需要保障服务器的稳定运行;需要对提供的接口进行限流控制。避免因客户端频繁的请求导致服务器的压力。

一、AspNetCoreRateLimit 介绍

 AspNetCoreRateLimit是一个ASP.NET Core速率限制的解决方案,旨在控制客户端根据IP地址或客户端ID向Web API或MVC应用发出的请求的速率。AspNetCoreRateLimit包含一个IpRateLimitMiddlewareClientRateLimitMiddleware,每个中间件可以根据不同的场景配置限制允许IP或客户端,自定义这些限制策略,也可以将限制策略应用在每个API URL或具体的HTTP Method上。

二、AspNetCoreRateLimit使用

 由上面介绍可知AspNetCoreRateLimit支持了两种方式:基于客户端IP(IpRateLimitMiddleware)和客户端ID(ClientRateLimitMiddleware)速率限制 接下来就分别说明使用方式

 添加Nuget包引用:

 Install-Package AspNetCoreRateLimit
  • 基于客户端IP速率限制

  1、修改Startup.cs中方法:

public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration
= configuration;
}

public IConfiguration Configuration { get; }// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//需要从加载配置文件appsettings.json
services.AddOptions();
//需要存储速率限制计算器和ip规则
services.AddMemoryCache();

//从appsettings.json中加载常规配置,IpRateLimiting与配置文件中节点对应
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));

//从appsettings.json中加载Ip规则
services.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies"));

//注入计数器和规则存储
services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
services.AddSingleton
<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();

services.AddControllers();

services.AddSingleton
<IHttpContextAccessor, HttpContextAccessor>();
//配置(解析器、计数器密钥生成器)
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();

//Other Code
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//Other Code

app.UseRouting();

app.UseAuthorization();
     //启用客户端IP限制速率
app.UseIpRateLimiting();

app.UseEndpoints(endpoints
=>
{
endpoints.MapControllers();
});
}
}

  2、在appsettings.json中添加通用配置项节点:(IpRateLimiting节点与Startup中取的节点对应)

"IpRateLimiting": {
//false,则全局将应用限制,并且仅应用具有作为端点的规则*。例如,如果您设置每秒5次调用的限制,则对任何端点的任何HTTP调用都将计入该限制
//true, 则限制将应用于每个端点,如{HTTP_Verb}{PATH}。例如,如果您为*:/api/values客户端设置每秒5个呼叫的限制,
"EnableEndpointRateLimiting": false,
//false,拒绝的API调用不会添加到调用次数计数器上;如 客户端每秒发出3个请求并且您设置了每秒一个调用的限制,则每分钟或每天计数器等其他限制将仅记录第一个调用,即成功的API调用。如果您希望被拒绝的API调用计入其他时间的显示(分钟,小时等)
//,则必须设置StackBlockedRequests为true。

"StackBlockedRequests": false,
//Kestrel 服务器背后是一个反向代理,如果你的代理服务器使用不同的页眉然后提取客户端IP X-Real-IP使用此选项来设置
"RealIpHeader": "X-Real-IP",
//取白名单的客户端ID。如果此标头中存在客户端ID并且与ClientWhitelist中指定的值匹配,则不应用速率限制。
"ClientIdHeader": "X-ClientId",
//限制状态码
"HttpStatusCode": 429,
////IP白名单:支持Ip v4和v6
//"IpWhitelist": [ "127.0.0.1", "::1/10", "192.168.0.0/24" ],
////端点白名单
//"EndpointWhitelist": [ "get:/api/license", "*:/api/status" ],
////客户端白名单
//"ClientWhitelist": [ "dev-id-1", "dev-id-2" ],
//通用规则
"GeneralRules": [
{
//端点路径
"Endpoint": "*",
//时间段,格式:{数字}{单位};可使用单位:s, m, h, d
"Period": "1s",
//限制
"Limit": 2
},
   //15分钟只能调用100次
{
"Endpoint": "*","Period": "15m","Limit": 100},
   //12H只能调用1000
{
"Endpoint": "*","Period": "12h","Limit": 1000},
   //7天只能调用10000次
{
"Endpoint": "*","Period": "7d","Limit": 10000}
]
}

   配置节点已添加相应注释信息。

   规则设置格式:   

端点格式:{HTTP_Verb}:{PATH},您可以使用asterix符号来定位任何HTTP谓词。

期间格式:{INT}{PERIOD_TYPE},您可以使用以下期间类型之一:s, m, h, d

限制格式:{LONG}

  3、特点Ip限制规则设置,在appsettings.json中添加 IP规则配置节点

"IpRateLimitPolicies": {
//ip规则
"IpRules": [
{
//IP
"Ip": "84.247.85.224",
//规则内容
"Rules": [
//1s请求10次
{"Endpoint": "*","Period": "1s","Limit": 10},
//15分钟请求200次
{"Endpoint": "*","Period": "15m","Limit": 200}
]
},
{
//ip支持设置多个
"Ip": "192.168.3.22/25",
"Rules": [
//1秒请求5次
{"Endpoint": "*","Period": "1s","Limit": 5},
//15分钟请求150次
{"Endpoint": "*","Period": "15m","Limit": 150},
//12小时请求500次
{"Endpoint": "*","Period": "12h","Limit": 500}
]
}
]
}

  • 基于客户端ID速率限制

  1、修改Startup文件:

public void ConfigureServices(IServiceCollection services)
{
//需要从加载配置文件appsettings.json
services.AddOptions();

//需要存储速率限制计算器和ip规则
services.AddMemoryCache();

//从appsettings.json中加载常规配置
services.Configure<ClientRateLimitOptions>(Configuration.GetSection("IPRateLimiting"));

//从appsettings.json中加载客户端规则
services.Configure<ClientRateLimitPolicies>(Configuration.GetSection("ClientRateLimitPolicies"));

//注入计数器和规则存储
services.AddSingleton<IClientPolicyStore, MemoryCacheClientPolicyStore>();
services.AddSingleton
<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();


services.AddControllers();

// https://github.com/aspnet/Hosting/issues/793
// the IHttpContextAccessor service is not registered by default.
//注入计数器和规则存储
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

//配置(解析器、计数器密钥生成器)
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//启用客户端限制
app.UseClientRateLimiting();

app.UseMvc();
}

  2、通用配置采用IP限制相同配置,添加客户端限制配置:

//客户端限制设置
"ClientRateLimitPolicies": {
"ClientRules": [
{
//客户端id
"ClientId": "client-id-1",
"Rules": [
{
"Endpoint": "*","Period": "1s","Limit": 10},
{
"Endpoint": "*","Period": "15m","Limit": 200}
]
},
{
"ClientId": "client-id-2",
"Rules": [
{
"Endpoint": "*","Period": "1s","Limit": 5},
{
"Endpoint": "*","Period": "15m","Limit": 150},
{
"Endpoint": "*","Period": "12h","Limit": 500}
]
}
]
}

  3、调用结果:

    设置规则:1s只能调用一次:首次调用

    

     调用第二次:自定义返回内容

     

三、其他 

  • 运行时更新速率限制

   添加IpRateLimitController控制器:   

/// <summary>
/// IP限制控制器
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class IpRateLimitController : ControllerBase
{

private readonly IpRateLimitOptions _options;
private readonly IIpPolicyStore _ipPolicyStore;

/// <summary>
///
/// </summary>
/// <param name="optionsAccessor"></param>
/// <param name="ipPolicyStore"></param>
public IpRateLimitController(IOptions<IpRateLimitOptions> optionsAccessor, IIpPolicyStore ipPolicyStore)
{
_options
= optionsAccessor.Value;
_ipPolicyStore
= ipPolicyStore;
}

/// <summary>
/// 获取限制规则
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<IpRateLimitPolicies> Get()
{
return await _ipPolicyStore.GetAsync(_options.IpPolicyPrefix);
}

/// <summary>
///
/// </summary>
[HttpPost]
public async Task Post(IpRateLimitPolicy ipRate)
{
var pol = await _ipPolicyStore.GetAsync(_options.IpPolicyPrefix);
if (ipRate != null)
{

pol.IpRules.Add(ipRate);
await _ipPolicyStore.SetAsync(_options.IpPolicyPrefix, pol);
}
}
}

  • 分布式部署时,需要将速率限制计算器和ip规则存储到分布式缓存中如Redis

    • 修改注入对象

// inject counter and rules distributed cache stores
services.AddSingleton<IClientPolicyStore, DistributedCacheClientPolicyStore>();
services.AddSingleton
<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();

    • 添加Nuget包 Microsoft.Extensions.Caching.StackExchangeRedis 

    • 在Startup中设置Redis连接

services.AddStackExchangeRedisCache(options =>
{
options.ConfigurationOptions
= new ConfigurationOptions
{
//silently retry in the background if the Redis connection is temporarily down
AbortOnConnectFail = false
};
options.Configuration
= "localhost:6379";
options.InstanceName
= "AspNetRateLimit";
});

  • 限制时自定义相应结果:

    //请求返回
    "QuotaExceededResponse": {
    "Content": "{{\"code\":429,\"msg\":\"Visit too frequently, please try again later\",\"data\":null}}",
    "ContentType": "application/json;utf-8",
    "StatusCode": 429
    },

     调用时返回结果:

其他:

  示例代码:https://github.com/cwsheng/WebAPIVersionDemo


往期精彩回顾




【推荐】.NET Core开发实战视频课程 ★★★

.NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划

【.NET Core微服务实战-统一身份认证】开篇及目录索引

Redis基本使用及百亿数据量中的使用技巧分享(附视频地址及观看指南)

.NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了

10个小技巧助您写出高性能的ASP.NET Core代码

用abp vNext快速开发Quartz.NET定时任务管理界面

在ASP.NET Core中创建基于Quartz.NET托管服务轻松实现作业调度

现身说法:实际业务出发分析百亿数据量下的多表查询优化

关于C#异步编程你应该了解的几点建议

C#异步编程看这篇就够了


浏览 53
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报