using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Ropin.Core.Common; using System.Threading; namespace Ropin.Core.Extensions { [AttributeUsage(AttributeTargets.Method, Inherited = true)] /// /// 限制多出频繁请求 /// /// /// api request idempotence /// public class HttpIdempotentAttribute : Attribute, IAsyncResourceFilter { static HttpIdempotentAttribute() { var thread = new Thread(() => { while (true) { var hashtableDatas = HashTable.Where(x => DateTime.Now > x.Value.Time).ToList(); if (hashtableDatas.Any()) { foreach (var hashtableData in hashtableDatas) { HashTable.Remove(hashtableData.Key); } } else { System.Threading.Thread.Sleep(2000); } } }); thread.IsBackground = true; thread.Start(); } /// /// http request parameter code collect /// private static readonly Dictionary HashTable = new(); /// /// http request parameter code /// public int _httpHasCode; /// /// waiting for the last request , default value:1000 /// public double WaitMillisecond { get; set; } = 1000; /// /// result cache Millisecond , default value:1000 /// public double CacheMillisecond { get; set; } = 1000; /// /// interceptor /// /// /// /// public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { await this.SetHttpParameterHasCode(context.HttpContext); if (HashTable.ContainsKey(_httpHasCode)) { var hashtableData = (HashtableData)HashTable[_httpHasCode]; if (hashtableData != null) { if (DateTime.Now < hashtableData.Time) { context.Result = hashtableData.Value; return; } else if (DateTime.Now > hashtableData.Time) { HashTable.Remove(_httpHasCode); } else if (hashtableData.Value == null) { context.Result = new ContentResult() { Content = "正在执行..." }; //context.Result = new ObjectResult("正在执行...") //{ // StatusCode = StatusCodes.Status500InternalServerError //}; return; } } } HashTable.Add(_httpHasCode, new HashtableData(DateTime.Now.AddMilliseconds(WaitMillisecond), null)); try { var netResult = await next(); if (HashTable.ContainsKey(_httpHasCode)) { var hashtableData = (HashtableData)HashTable[_httpHasCode]; if (hashtableData != null) { hashtableData.Value = (IActionResult)netResult.Result; hashtableData.Time = DateTime.Now.AddMilliseconds(CacheMillisecond); } } } catch (Exception ex) { HashTable.Remove(_httpHasCode); } } /// /// get http request parameter code /// /// private async Task SetHttpParameterHasCode(HttpContext httpContext) { object readFromJson = null; try { if (httpContext.Request.Method != "GET") { //readFromJson = await httpContext.Request.ReadFromJsonAsync(); httpContext.Request.EnableBuffering();//设置流可以多次读取 readFromJson = await new StreamReader(httpContext.Request.Body).ReadToEndAsync(); httpContext.Request.Body.Seek(0, SeekOrigin.Begin);//设置流的栈位置回到起点 } } catch (Exception e) { Console.WriteLine(e); } //todo 根据实际项目情况处理,获取Headers toke var authorization = httpContext.Request.Headers["Authorization"]; var queryString = httpContext.Request.QueryString; var bodyString = readFromJson == null ? string.Empty : readFromJson.ToString(); var builder = $"{authorization}-{queryString}-{bodyString}"; this._httpHasCode = builder.GetHashCode(); } /// /// Hashtable parameter model /// private class HashtableData { public HashtableData(DateTime time, ObjectResult value) { Time = time; Value = value; } public DateTime Time { get; set; } public IActionResult Value { get; set; } } } }