限流 控制

请求是从一个白名单中的IP或客户端key发起的,那么限流策略将不会生效,这个请求的所有信息也不会被存储。 其IP白名单列表支持IP v4和v6的范围配置,比如"192.168.0.0/24", "fe80::/10" 和 "192.168.0.0-192.168.0.255",关于IP范围的更多信息请查看https://github.com/jsakamoto/ipaddressrange

复制代码
config.MessageHandlers.Add(new ThrottlingHandler()
{
    Policy = new ThrottlePolicy(perSecond: 2, perMinute: 60)
    {
        IpThrottling = true,
        IpWhitelist = new List<string> { "::1", "192.168.0.0/24" },

        ClientThrottling = true,
        ClientWhitelist = new List<string> { "admin-key" }
    },
    Repository = new CacheRepository()
});
复制代码

IP和客户端key自定义限制频率

你可以自定义基于ip或客户端key的请求频率限制,这些限制会重写WebApiThrottle的默认配置。

需要注意的是,这些自定义策略需要写到全局配置里才会生效,策略里可以单独给某个ip或某个key配置限流策略。

复制代码
config.MessageHandlers.Add(new ThrottlingHandler()
{
    Policy = new ThrottlePolicy(perSecond: 1, perMinute: 20, perHour: 200, perDay: 1500)
    {
        IpThrottling = true,
        IpRules = new Dictionary<string, RateLimits>
        { 
            { "192.168.1.1", new RateLimits { PerSecond = 2 } },
            { "192.168.2.0/24", new RateLimits { PerMinute = 30, PerHour = 30*60, PerDay = 30*60*24 } }
        },

        ClientThrottling = true,
        ClientRules = new Dictionary<string, RateLimits>
        { 
            { "api-client-key-1", new RateLimits { PerMinute = 40, PerHour = 400 } },
            { "api-client-key-9", new RateLimits { PerDay = 2000 } }
        }
    },
    Repository = new CacheRepository()
});
复制代码

端点自定义限制频率

你也可以为明确的路由地址去自定义限制频率,这些限制配置会重写WebApiThrottle的默认配置。也可以通过相关联的路由地址去定义端点的限制规则,比如api/entry/1端点的请求仅仅是/entry/整个路由地址请求的一部分。 配置后,端点限制引擎会在请求的绝对URI中去搜索这个表达式(api/entry/1),如果这个表达式在请求路由策略中被找到,那么这个限制规则将会被应用。如果有两个或更多的限制规则匹配到同一个URL,更近一级的限制策略将会被应用。

复制代码
config.MessageHandlers.Add(new ThrottlingHandler()
{
    Policy = new ThrottlePolicy(perSecond: 1, perMinute: 20, perHour: 200)
    {
        IpThrottling = true,
        ClientThrottling = true,
        EndpointThrottling = true,
        EndpointRules = new Dictionary<string, RateLimits>
        { 
            { "api/search", new RateLimits { PerSecond = 10, PerMinute = 100, PerHour = 1000 } }
        }
    },
    Repository = new CacheRepository()
});
复制代码

关于被拒请求的计数器

默认情况下,被拒绝的请求不会累加到WebApiThrottle的计数器里。 比如一个客户端在同一秒中请求了3次,而你配置的限制策略是每秒1次,那么分钟、小时、天的计数器只会记录第一次调用,因为第一次请求不会被拒绝。如果你想把被拒绝的请求也计算到其他的计数器里(分钟、小时、天),你可以设置StackBlockedRequests为true。

复制代码
config.MessageHandlers.Add(new ThrottlingHandler()
{
    Policy = new ThrottlePolicy(perSecond: 1, perMinute: 30)
    {
        IpThrottling = true,
        ClientThrottling = true,
        EndpointThrottling = true,
        StackBlockedRequests = true
    },
    Repository = new CacheRepository()
});
复制代码

在web.config或app.config中定义限制策略

在web.config或app.config中配置限制策略,通过ThrottlePolicy.FromStore加装配置项。

config.MessageHandlers.Add(new ThrottlingHandler()
{
    Policy = ThrottlePolicy.FromStore(new PolicyConfigurationProvider()),
    Repository = new CacheRepository()
});

配置示例(policyType的值1代表ip、2代表clientkey、3代表端点)

复制代码
<configuration>

  <configSections>
    <section name="throttlePolicy" 
             type="WebApiThrottle.ThrottlePolicyConfiguration, WebApiThrottle" />
  </configSections>

  <throttlePolicy limitPerSecond="1"
                  limitPerMinute="10"
                  limitPerHour="30"
                  limitPerDay="300"
                  limitPerWeek ="1500"
                  ipThrottling="true"
                  clientThrottling="true"
                  endpointThrottling="true">
    <rules>
      <!--Ip 规则-->
      <add policyType="1" entry="::1/10"
           limitPerSecond="2"
           limitPerMinute="15"/>
      <add policyType="1" entry="192.168.2.1"
           limitPerMinute="12" />
      <!--Client 规则-->
      <add policyType="2" entry="api-client-key-1"
           limitPerHour="60" />
      <!--Endpoint 规则-->
      <add policyType="3" entry="api/values"
           limitPerDay="120" />
    </rules>
    <whitelists>
      <!--Ip 白名单-->
      <add policyType="1" entry="127.0.0.1" />
      <add policyType="1" entry="192.168.0.0/24" />
      <!--Client 白名单-->
      <add policyType="2" entry="api-admin-key" />
    </whitelists>
  </throttlePolicy>
</configuration>
复制代码

获取API的客户端key

默认情况下,WebApiThrottle的ThrottlingHandler(限流处理器)会从客户端请求head里通过Authorization-Token key取值。如果你的API key存储在不同的地方,你可以重写ThrottlingHandler.SetIndentity方法,指定你自己的取值策略。

复制代码
public class CustomThrottlingHandler : ThrottlingHandler
{
    protected override RequestIdentity SetIndentity(HttpRequestMessage request)
    {
        return new RequestIdentity()
        {
            ClientKey = request.Headers.Contains("Authorization-Key") ? request.Headers.GetValues("Authorization-Key").First() : "anon",
            ClientIp = base.GetClientIp(request).ToString(),
            Endpoint = request.RequestUri.AbsolutePath.ToLowerInvariant()
        };
    }
}
复制代码

存储限流的数据

WebApiThrottle会在内存中存储所有的请求数据,寄宿在IIS里使用ASP.NET版本的cache、自寄宿在Owin上使用运行时版本的缓存MemoryCache。如果你想改变请求数据存储的策略,框架是支持redis、nosql、数据库存储的,这种情况下必须创建自己的存储引擎,可以通过实现IThrottleRepository接口完成。

复制代码
public interface IThrottleRepository { bool Any(string id);

ThrottleCounter? FirstOrDefault(string id);

void Save(string id, ThrottleCounter throttleCounter, TimeSpan expirationTime);

void Remove(string id);

void Clear();
}
复制代码

自从1.2版本后有IPolicyRepository的接口可以实现存储、获取限制策略对象,意味着可以持久化限流策略,同时也可以被用于在运行期间动态更新限制策略对象。

复制代码
public interface IPolicyRepository
{
    ThrottlePolicy FirstOrDefault(string id);

    void Remove(string id);

    void Save(string id, ThrottlePolicy policy);
}
复制代码

运行期间更新限制频率

为了更新限制策略对象,并在运行时使用新的ThrottlingHandler对象,需要引入WebApiThrottle 1.2版本后支持的ThrottleManager.UpdatePolicy函数。

在启动时注册ThrottlingHandler对象,并在构造函数中传入PolicyCacheRepository ,如果你是通过Owin自寄宿的webapi,需要使用PolicyMemoryCacheRepository对象。

复制代码
public static void Register(HttpConfiguration config)
{
    //trace provider
    var traceWriter = new SystemDiagnosticsTraceWriter()
    {
        IsVerbose = true
    };
    config.Services.Replace(typeof(ITraceWriter), traceWriter);
    config.EnableSystemDiagnosticsTracing();

    //添加限流处理者到Web API消息处理集合里
    config.MessageHandlers.Add(new ThrottlingHandler(
        policy: new ThrottlePolicy(perMinute: 20, perHour: 30, perDay: 35, perWeek: 3000)
        {
            //启用ip限制策略
            IpThrottling = true,

            //启用客户端key限制策略
            ClientThrottling = true,
            ClientRules = new Dictionary<string, RateLimits>
            { 
                { "api-client-key-1", new RateLimits { PerMinute = 60, PerHour = 600 } },
                { "api-client-key-2", new RateLimits { PerDay = 5000 } }
            },

            //启用端点限制策略
            EndpointThrottling = true
        },

        //如果是owin寄宿,替换成PolicyMemoryCacheRepository
        policyRepository: new PolicyCacheRepository(),

        //如果是owin寄宿,替换成MemoryCacheRepository 
        repository: new CacheRepository(),

        logger: new TracingThrottleLogger(traceWriter)));
}
复制代码

当你想更新限制策略对象时,可以在任何你的代码里调用静态方法ThrottleManager.UpdatePolicy去刷新内存中的策略数据。

复制代码
public void UpdateRateLimits()
{
    //初始化策略仓库
    var policyRepository = new PolicyCacheRepository();

    //从缓存中获取策略对象
    var policy = policyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey());

    //更新客户端限制频率
    policy.ClientRules["api-client-key-1"] =
        new RateLimits { PerMinute = 80, PerHour = 800 };

    //添加新的客户端限制频率
    policy.ClientRules.Add("api-client-key-3",
        new RateLimits { PerMinute = 60, PerHour = 600 });

    //应用策略更新
    ThrottleManager.UpdatePolicy(policy, policyRepository);

}
复制代码

限流的请求日志

如果你想记录限流后的请求日志,可以实现IThrottleLogger接口,添加到ThrottlingHandler里。

public interface IThrottleLogger
{
    void Log(ThrottleLogEntry entry);
}

实现ITraceWriter日志记录接口的例子

复制代码
public class TracingThrottleLogger : IThrottleLogger
{
    private readonly ITraceWriter traceWriter;

    public TracingThrottleLogger(ITraceWriter traceWriter)
    {
        this.traceWriter = traceWriter;
    }

    public void Log(ThrottleLogEntry entry)
    {
        if (null != traceWriter)
        {
            traceWriter.Info(entry.Request, "WebApiThrottle",
                "{0} Request {1} from {2} has been throttled (blocked), quota {3}/{4} exceeded by {5}",
                entry.LogDate, entry.RequestId, entry.ClientIp, entry.RateLimit, entry.RateLimitPeriod, entry.TotalRequests);
        }
    }
}
复制代码

用SystemDiagnosticsTraceWriter和ThrottlingHandler记录日志的使用例子:

复制代码
var traceWriter = new SystemDiagnosticsTraceWriter()
{
    IsVerbose = true
};
config.Services.Replace(typeof(ITraceWriter), traceWriter);
config.EnableSystemDiagnosticsTracing();

config.MessageHandlers.Add(new ThrottlingHandler()
{
    Policy = new ThrottlePolicy(perSecond: 1, perMinute: 30)
    {
        IpThrottling = true,
        ClientThrottling = true,
        EndpointThrottling = true
    },
    Repository = new CacheRepository(),
    Logger = new TracingThrottleLogger(traceWriter)
});
复制代码

用ThrottlingFilter、EnableThrottlingAttribute特性配置限制频率

EnableThrottling与ThrottlingHandler是一个二选一的策略配置方案,二者会做同样的事情,但ThrottlingHandler可以通过EnableThrottlingAttribute特性指定某个webapi的controllers和actions去自定义频率限制。需要注意的是,在webapi请求管道中,ThrottlingHandler是在controller前面执行,因此在你不需要ThrottlingFilter提供的功能时,可以用ThrottlingHandler去直接替代它。

设置ThrottlingFilter过滤器的步骤,跟ThrottlingHandler类似:

复制代码
config.Filters.Add(new ThrottlingFilter()
{
    Policy = new ThrottlePolicy(perSecond: 1, perMinute: 20, 
    perHour: 200, perDay: 2000, perWeek: 10000)
    {
        //ip配置区域
        IpThrottling = true,
        IpRules = new Dictionary<string, RateLimits>
        { 
            { "::1/10", new RateLimits { PerSecond = 2 } },
            { "192.168.2.1", new RateLimits { PerMinute = 30, PerHour = 30*60, PerDay = 30*60*24 } }
        },
        //添加127.0.0.1到白名单,本地地址不启用限流策略
        IpWhitelist = new List<string> { "127.0.0.1", "192.168.0.0/24" },

        //客户端配置区域,如果ip限制也是启动的,那么客户端限制策略会与ip限制策略组合使用。
        ClientRules = new Dictionary<string, RateLimits>
        { 
            { "api-client-key-demo", new RateLimits { PerDay = 5000 } }
        },
        //白名单中的客户端key不会进行限流。
        ClientWhitelist = new List<string> { "admin-key" },

        //端点限制策略配置会从EnableThrottling特性中获取。
        EndpointThrottling = true
    }
});
复制代码

使用特性开启限流并配置限制频率:

复制代码
[EnableThrottling(PerSecond = 2)]
public class ValuesController : ApiController
{
    [EnableThrottling(PerSecond = 1, PerMinute = 30, PerHour = 100)]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    [DisableThrotting]
    public string Get(int id)
    {
        return "value";
    }
}
复制代码

关于ThrottlingMiddleware限制频率

ThrottlingMiddleware是一个OWIN中间件部分,它的作用跟ThrottlingHandler一样。使用ThrottlingMiddleware 你可以在webapi作用域范围外配置限制策略,跟使用OAuth中间件或SignalR端点类似。

自寄宿配置例子:

复制代码
public class Startup
{
    public void Configuration(IAppBuilder appBuilder)
    {
        ...

        //从app.config加载限流策略
        appBuilder.Use(typeof(ThrottlingMiddleware),
            ThrottlePolicy.FromStore(new PolicyConfigurationProvider()),
            new PolicyMemoryCacheRepository(),
            new MemoryCacheRepository(),
            null);

        ...
    }
}
复制代码

IIS寄宿配置例子:

复制代码
public class Startup
{
    public void Configuration(IAppBuilder appBuilder)
    {
        ...

    //从web.config加载限流策略
    appBuilder.Use(typeof(ThrottlingMiddleware),
        ThrottlePolicy.FromStore(new PolicyConfigurationProvider()),
        new PolicyCacheRepository(),
        new CacheRepository(),
        null);

        ...
    }
}
复制代码

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值