龙空技术网

Asp.NET Core 限流控制

IT人张飞洪 903

前言:

现在我们对“aspnet不稳定”大致比较重视,姐妹们都需要了解一些“aspnet不稳定”的相关资讯。那么小编也在网络上汇集了一些关于“aspnet不稳定””的相关文章,希望小伙伴们能喜欢,兄弟们快快来学习一下吧!

起因:

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

一、AspNetCoreRateLimit 介绍

 AspNetCoreRateLimit是一个ASP.NET Core速率限制的解决方案,旨在控制客户端根据IP地址或客户端ID向Web API或MVC应用发出的请求的速率。AspNetCoreRateLimit包含一个IpRateLimitMiddleware和ClientRateLimitMiddleware,每个中间件可以根据不同的场景配置限制允许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();        //         // 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 storesservices.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 },

   调用时返回结果:

标签: #aspnet不稳定 #netmvc计算器 #aspnet缓存的问题不一定成功 #aspnet接口频率限制 #aspnet截取字符