using System; using System.Diagnostics; using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Lottomat.Application.Code; using Lottomat.Application.Entity.CommonEntity; using Lottomat.SOA.API.Caching; using Lottomat.Util.Extension; namespace Lottomat.SOA.API.Handlers { /// /// 请求频率限制 /// public sealed class RequestFrequencyLimitHandlers : DelegatingHandler { private readonly IThrottleStore _store; private readonly Func _maxRequestsForUserIdentifier; private readonly TimeSpan _period; private readonly string _message; private RequestFrequencyLimitHandlers() { } /// /// 构造 /// /// /// /// /// public RequestFrequencyLimitHandlers(IThrottleStore store, Func maxRequestsForUserIdentifier, TimeSpan period, string message = "对不起,您的请求频率过高({0}次/分钟),请稍后再试。") { _store = store; _maxRequestsForUserIdentifier = maxRequestsForUserIdentifier; _period = period; _message = message; } /// /// 获取请求IP地址 /// /// /// private string GetUserIdentifier(HttpRequestMessage request) { return request.GetClientIpAddress(); } protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { //Key,即IP地址 string identifier = GetUserIdentifier(request); if (string.IsNullOrEmpty(identifier)) { return CreateResponse(request, HttpStatusCode.Forbidden, "无法识别客户机."); } long maxRequests = _maxRequestsForUserIdentifier(identifier); Trace.WriteLine("IP地址为:" + identifier + ",请求了服务。"); if (_store.TryGetValue(identifier, out ThrottleEntry entry)) { if (entry.PeriodStart + _period < DateTime.UtcNow) { _store.Rollover(identifier); } } _store.IncrementRequests(identifier); if (!_store.TryGetValue(identifier, out entry)) { return CreateResponse(request, HttpStatusCode.Forbidden, "无法识别客户机."); } Task response = entry.Requests > maxRequests ? CreateResponse(request, HttpStatusCode.Conflict, string.Format(_message, maxRequests)) : base.SendAsync(request, cancellationToken); return response.ContinueWith(task => { long remaining = maxRequests - entry.Requests; if (remaining < 0) { remaining = 0; } HttpResponseMessage httpResponse = task.Result; httpResponse.Headers.Add("RateLimit-Limit", maxRequests.ToString()); httpResponse.Headers.Add("RateLimit-Remaining", remaining.ToString()); Trace.WriteLine("剩余可调用次数为:" + remaining); return httpResponse; }, cancellationToken); } /// /// 返回到客户端的消息 /// /// /// /// /// private Task CreateResponse(HttpRequestMessage request, HttpStatusCode statusCode, string message) { BaseJson resultMsg = new BaseJson { Status = (int)JsonObjectStatus.Fail, Message = message, Data = null }; TaskCompletionSource tsc = new TaskCompletionSource(); HttpResponseMessage response = resultMsg.TryToJson().ToHttpResponseMessage(); //request.CreateResponse(statusCode); //response.ReasonPhrase = message; tsc.SetResult(response); return tsc.Task; } } }