IdempotentAttribute.cs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // 此源代码遵循位于源代码树根目录中的 LICENSE 文件的许可证。
  2. //
  3. // 必须在法律法规允许的范围内正确使用,严禁将其用于非法、欺诈、恶意或侵犯他人合法权益的目的。
  4. using System.Security.Claims;
  5. namespace Admin.NET.Core;
  6. /// <summary>
  7. /// 防止重复请求过滤器特性
  8. /// </summary>
  9. public class IdempotentAttribute : Attribute, IAsyncActionFilter
  10. {
  11. /// <summary>
  12. /// 请求间隔时间/秒
  13. /// </summary>
  14. public int IntervalTime { get; set; } = 5;
  15. /// <summary>
  16. /// 错误提示内容
  17. /// </summary>
  18. public string Message { get; set; } = "你操作频率过快,请稍后重试!";
  19. /// <summary>
  20. /// 缓存前缀: Key+请求路由+用户Id+请求参数
  21. /// </summary>
  22. public string CacheKey { get; set; }
  23. /// <summary>
  24. /// 是否直接抛出异常:Ture是,False返回上次请求结果
  25. /// </summary>
  26. public bool ThrowBah { get; set; }
  27. public IdempotentAttribute()
  28. {
  29. }
  30. public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
  31. {
  32. var httpContext = context.HttpContext;
  33. var path = httpContext.Request.Path.Value.ToString();
  34. var userId = httpContext.User?.FindFirstValue(ClaimConst.UserId);
  35. var cacheExpireTime = TimeSpan.FromSeconds(IntervalTime);
  36. var parameters = "";
  37. foreach (var parameter in context.ActionDescriptor.Parameters)
  38. {
  39. parameters += parameter.Name;
  40. parameters += context.ActionArguments[parameter.Name].ToJson();
  41. }
  42. var cacheKey = MD5Encryption.Encrypt($"{CacheKey}{path}{userId}{parameters}");
  43. var sysCacheService = App.GetService<SysCacheService>();
  44. if (sysCacheService.ExistKey(cacheKey))
  45. {
  46. if (ThrowBah) throw Oops.Oh(Message);
  47. try
  48. {
  49. var cachedResult = sysCacheService.Get<ResponseData>(cacheKey);
  50. context.Result = new ObjectResult(cachedResult.Value);
  51. }
  52. catch (Exception ex)
  53. {
  54. throw Oops.Oh($"{Message}-{ex}");
  55. }
  56. }
  57. else
  58. {
  59. // 先加入一个空缓存,防止第一次请求结果没回来导致连续请求
  60. sysCacheService.Set(cacheKey, "", cacheExpireTime);
  61. var resultContext = await next();
  62. if (resultContext.Result is ObjectResult objectResult)
  63. {
  64. var valueType = objectResult.Value.GetType();
  65. var responseData = new ResponseData
  66. {
  67. Type = valueType.Name,
  68. Value = objectResult.Value
  69. };
  70. sysCacheService.Set(cacheKey, responseData, cacheExpireTime);
  71. }
  72. }
  73. }
  74. /// <summary>
  75. /// 请求结果数据
  76. /// </summary>
  77. private class ResponseData
  78. {
  79. /// <summary>
  80. /// 结果类型
  81. /// </summary>
  82. public string Type { get; set; }
  83. /// <summary>
  84. /// 请求结果
  85. /// </summary>
  86. public dynamic Value { get; set; }
  87. }
  88. }