当前位置: 首页 > article >正文

.NETCore WebApi阻止接口重复调用(并发操作)

客户的APP反馈重复提交数据,需要阻止接口重复调用。

分享一段代码给大家:

/*===================================================================
 *   程序说明: WebApi开发框架(.NET8+EFCore+AspNetCore)
 *            https://www.cscode.net/archive/webapi-netcore-v3/361414129516549.html
 *   原创作者: 珠海喜鹊信息技术有限公司
 *   创建日期: 2024/12/01 11:43:18
 *   最后修改: 2024/12/01 11:43:18 
 *   版权所有: Copyright 2006~2024, C/S框架网(www.csframework.com)
 *===================================================================*/
using CSFramework.WebApi.Common;
using CSFramework.WebApi.Core.Interfaces;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace CSFramework.WebApi.Core
{
    /// <summary>
    /// 不校验接口请求并发
    /// </summary>
    public class NotRequestConcurrentAttribute : BaseActionFilterAsyncAttribute { }

    /// <summary>
    /// 校验接口是否并发操作,重复请求(使用MemoryCache设置标记)
    /// </summary>
    public class RequestConcurrentAttribute : BaseActionFilterAsyncAttribute
    {
        public RequestConcurrentAttribute() { }

        /// <summary>
        /// 执行操作
        /// </summary>
        /// <param name="filterContext"></param>
        /// <returns></returns>
        public async override Task OnActionExecuting(ActionExecutingContext filterContext)
        {
            //判断是否需要接口请求并发
            if (filterContext.ContainsFilter<NotRequestConcurrentAttribute>())
            {
                await base.OnActionExecuting(filterContext);
                return;
            }

            //当前登录用户
            IUserContext user = Core.Globals.ServiceProvider.GetService<IUserContext>();

            //获取当前登录用户账号
            if (user.UserId.IsEmpty())
            {
                await base.OnActionExecuting(filterContext);
                return;
            }

            Console.WriteLine(">>RequestConcurrentAttribute.OnActionExecuting...");

            //获取缓存key值,如:"userId_9b80d5d0ebda4b11c4ba396cd4312f35"
            var key = GetCacheKey(user.UserId, filterContext.HttpContext.Request.Path);
            var cache = Core.Globals.ServiceProvider.GetService<IMemoryCache>();
            string value = cache.Get<String>(key);//从缓存获取key

            //有标记,并发操作!
            if (!value.IsEmpty())
            {
                var errMessage = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + " "
                    + "重复操作,系统已阻止。线程ID:"
                    + System.Threading.Thread.CurrentThread.ManagedThreadId;

                //保存数据日志
                var log = Core.Globals.ServiceProvider.GetService<IApiLogBusiness>();
                log.Log("concurrent", user.IP, "请求并发:" + errMessage);

                //删除缓存标记
                cache.Remove(key);

                throw new BizException(errMessage);
            }
            else
            {
                //设置缓存标记:同一个url,1秒内重复点击
                cache.Set<String>(key, "click", TimeSpan.FromSeconds(1));//设置1秒后自动过期。
            }

            await Task.CompletedTask;
        }

        public override Task OnActionExecuted(ActionExecutedContext context)
        {
            return base.OnActionExecuted(context);
        }

        /// <summary>
        /// 生成缓存key
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="requestPath"></param>
        /// <returns></returns>
        private string GetCacheKey(string userId, string requestPath)
        {
            string localPath = GetApiPath(requestPath);
            var key = userId + "_" + localPath.ToMD5String();
            return key;
        }

        /// <summary>
        /// 获取api接口名称,如:[api/common/get] => [common/get]
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private string GetApiPath(string path)
        {
            // 定义一个Regex对象实例
            Regex r = new Regex(@"(/api)?(/\S+)", RegexOptions.IgnoreCase);

            //在字符串中匹配
            Match m = r.Match(path);
            if (m.Success)
            {
                string local = m.Groups[2].Value;
                return local.ToLower();
            }

            return "";
        }
    }
}

控制器定义特性:

[ApiController]
[RequestConcurrentAttribute]
public class _BaseController : ControllerBase
{
    //省略代码......
}

若忽略并发操作:

[NotRequestConcurrent]
[HttpGet]
public string Test()
{
    return string.Empty;
}


http://www.kler.cn/a/499865.html

相关文章:

  • 硬件设计-齐纳管
  • 音视频入门基础:RTP专题(2)——使用FFmpeg命令生成RTP流
  • 湘潭大学人机交互复习
  • JVM实战—13.OOM的生产案例
  • Apache Hop从入门到精通 第一课 揭开Apache Hop神秘面纱
  • C# 语法中级
  • 后端技术选型 sa-token校验学习 下 结合项目学习 后端鉴权
  • 计算机网络 (36)TCP可靠传输的实现
  • python项目结构,PyCharm 调试Debug模式配置
  • winform第三方界面开源库AntdUI的使用教程保姆级环境设置篇
  • 信息系统项目管理-采购管理-采购清单示例
  • 2024.10.12 校招 实习 内推 面经
  • 【问题记录】解决小米手机无线投屏出现白屏什么都无法显示的问题
  • 【ROS2】☆ launch之Python
  • 重生之我在21世纪学C++—string
  • 【cuda学习日记】2.2 使用2维网络(grid)和2维块(block)对矩阵进行求和
  • 基于springboot+vue的高校创新创业课程体系的设计与实现
  • OpenAI掌舵人解读OpenAI新进展:迈向超级智能。
  • 传奇3仿韩服单机版安装教程+GM管理面板
  • 20250111面试鸭特训营第19天
  • postgresql|数据库|利用sqlparse和psycopg2库批量按顺序执行SQL语句(psyconpg2新优化版本)
  • 请求方式(基于注解实现)
  • vue.js 使用router-link替代a标签实现高亮