123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- 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)]
- /// <summary>
- /// 限制多出频繁请求
- /// </summary>
- /// <summary>
- /// api request idempotence
- /// </summary>
- 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();
- }
- /// <summary>
- /// http request parameter code collect
- /// </summary>
- private static readonly Dictionary<int, HashtableData> HashTable = new();
- /// <summary>
- /// http request parameter code
- /// </summary>
- public int _httpHasCode;
- /// <summary>
- /// waiting for the last request , default value:1000
- /// </summary>
- public double WaitMillisecond { get; set; } = 1000;
- /// <summary>
- /// result cache Millisecond , default value:1000
- /// </summary>
- public double CacheMillisecond { get; set; } = 1000;
- /// <summary>
- /// interceptor
- /// </summary>
- /// <param name="context"></param>
- /// <param name="next"></param>
- /// <returns></returns>
- 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);
- }
- }
- /// <summary>
- /// get http request parameter code
- /// </summary>
- /// <returns></returns>
- private async Task SetHttpParameterHasCode(HttpContext httpContext)
- {
- object readFromJson = null;
- try
- {
- if (httpContext.Request.Method != "GET")
- {
- //readFromJson = await httpContext.Request.ReadFromJsonAsync<object>();
- 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();
- }
- /// <summary>
- /// Hashtable parameter model
- /// </summary>
- private class HashtableData
- {
- public HashtableData(DateTime time, ObjectResult value)
- {
- Time = time;
- Value = value;
- }
- public DateTime Time { get; set; }
- public IActionResult Value { get; set; }
- }
- }
- }
|