# 幂等性处理 **本文档中引用的文件** - [AbpIdempotentModule.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/AbpIdempotentModule.cs) - [AbpIdempotentOptions.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/AbpIdempotentOptions.cs) - [IdempotentAttribute.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentAttribute.cs) - [IdempotentChecker.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentChecker.cs) - [IdempotentKeyNormalizer.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentKeyNormalizer.cs) - [AbpAspNetCoreMvcIdempotentModule.cs](file://aspnet-core/framework/mvc/LINGYUN.Abp.AspNetCore.Mvc.Idempotent/LINGYUN/Abp/AspNetCore/Mvc/Idempotent/AbpAspNetCoreMvcIdempotentModule.cs) - [AbpIdempotentActionFilter.cs](file://aspnet-core/framework/mvc/LINGYUN.Abp.AspNetCore.Mvc.Idempotent/LINGYUN/Abp/AspNetCore/Mvc/Idempotent/AbpIdempotentActionFilter.cs) - [AbpAspNetCoreMvcIdempotentOptions.cs](file://aspnet-core/framework/mvc/LINGYUN.Abp.AspNetCore.Mvc.Idempotent/LINGYUN/Abp/AspNetCore/Mvc/Idempotent/AbpAspNetCoreMvcIdempotentOptions.cs) - [AbpWrapIdempotentActionFilter.cs](file://aspnet-core/framework/mvc/LINGYUN.Abp.AspNetCore.Mvc.Idempotent.Wrapper/LINGYUN/Abp/AspNetCore/Mvc/Idempotent/Wrapper/AbpWrapIdempotentActionFilter.cs) - [IdempotentErrorCodes.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentErrorCodes.cs) - [IdempotentInterceptorRegistrar.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentInterceptorRegistrar.cs) ## 目录 1. [简介](#简介) 2. [技术架构](#技术架构) 3. [核心组件](#核心组件) 4. [配置方式](#配置方式) 5. [使用场景](#使用场景) 6. [最佳实践](#最佳实践) 7. [异常处理](#异常处理) 8. [代码示例](#代码示例) 9. [结论](#结论) ## 简介 幂等性处理是确保接口在多次调用时产生相同结果的重要机制,特别是在分布式系统和高并发场景下。LINGYUN.Abp.Idempotent模块提供了完整的幂等性解决方案,通过分布式锁和智能键生成机制,有效防止重复提交和数据不一致问题。该模块支持自动幂等性检查、自定义幂等键生成、灵活的超时配置,并与ABP框架无缝集成。 **Section sources** - [README.md](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/README.md) ## 技术架构 幂等性处理模块采用分层架构设计,包含配置层、拦截层、检查层和存储层。该架构通过AOP(面向切面编程)和MVC过滤器实现,确保在不侵入业务代码的情况下提供幂等性保护。 ```mermaid graph TD A[客户端请求] --> B{请求方法} B --> |POST/PUT/PATCH| C[AbpIdempotentActionFilter] B --> |其他方法| D[直接执行] C --> E[IdempotentKeyNormalizer] E --> F[生成幂等键] F --> G[IdempotentChecker] G --> H[分布式锁检查] H --> |已存在| I[返回429错误] H --> |不存在| J[执行业务逻辑] J --> K[释放分布式锁] K --> L[返回结果] ``` **Diagram sources ** - [AbpIdempotentActionFilter.cs](file://aspnet-core/framework/mvc/LINGYUN.Abp.AspNetCore.Mvc.Idempotent/LINGYUN/Abp/AspNetCore/Mvc/Idempotent/AbpIdempotentActionFilter.cs) - [IdempotentChecker.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentChecker.cs) - [IdempotentKeyNormalizer.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentKeyNormalizer.cs) ## 核心组件 ### 幂等性检查器 (IdempotentChecker) `IdempotentChecker`是幂等性处理的核心组件,实现了`IIdempotentChecker`接口。它利用分布式锁机制来确保同一操作在指定时间内只能执行一次。检查器首先验证全局配置是否启用幂等性,然后检查方法是否标记了`IgnoreIdempotent`属性以决定是否跳过检查。 ```mermaid classDiagram class IIdempotentChecker { <> +Task IsGrantAsync(IdempotentCheckContext context) } class IdempotentChecker { -IAbpDistributedLock _distributedLock -AbpIdempotentOptions _idempotentOptions +Task IsGrantAsync(IdempotentCheckContext context) } class IdempotentCheckContext { +Type Target +MethodInfo Method +string IdempotentKey +IReadOnlyDictionary ArgumentsDictionary } IIdempotentChecker <|.. IdempotentChecker ``` **Diagram sources ** - [IIdempotentChecker.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IIdempotentChecker.cs) - [IdempotentChecker.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentChecker.cs) - [IdempotentCheckContext.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentCheckContext.cs) **Section sources** - [IdempotentChecker.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentChecker.cs) ### 幂等键规范化器 (IdempotentKeyNormalizer) `IdempotentKeyNormalizer`负责生成唯一的幂等键,这是幂等性处理的关键。它根据方法的类型、名称和参数生成一个MD5哈希值作为唯一标识。规范化器支持多种键生成策略,包括自定义键、参数映射和默认序列化。 ```mermaid flowchart TD Start([开始]) --> CheckAttribute{"有IdempotentAttribute?"} CheckAttribute --> |是| CheckCustomKey{"有自定义键?"} CheckCustomKey --> |是| UseCustomKey["使用自定义键"] CheckCustomKey --> |否| UseKeyMap{"有KeyMap?"} UseKeyMap --> |是| BuildFromKeyMap["根据KeyMap构建"] UseKeyMap --> |否| BuildFromAllArgs["序列化所有参数"] CheckAttribute --> |否| BuildFromAllArgs BuildFromKeyMap --> FormatKey["格式化键: t:type;m:method;k:md5"] BuildFromAllArgs --> FormatKey FormatKey --> End([返回幂等键]) ``` **Diagram sources ** - [IdempotentKeyNormalizer.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentKeyNormalizer.cs) - [IdempotentKeyNormalizerContext.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentKeyNormalizerContext.cs) **Section sources** - [IdempotentKeyNormalizer.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentKeyNormalizer.cs) ### MVC动作过滤器 (AbpIdempotentActionFilter) `AbpIdempotentActionFilter`是MVC层面的幂等性实现,作为动作过滤器集成到ASP.NET Core管道中。它负责在控制器动作执行前进行幂等性检查,支持通过HTTP头传递幂等令牌或自动生成。 ```mermaid sequenceDiagram participant Client as "客户端" participant Filter as "AbpIdempotentActionFilter" participant Checker as "IdempotentChecker" participant Lock as "分布式锁" Client->>Filter : 发送请求 Filter->>Filter : ShouldCheckIdempotent() alt 需要检查 Filter->>Filter : 获取幂等键 alt 有X-With-Idempotent-Token头 Filter->>Filter : 使用头中的值 else Filter->>Filter : 调用IdempotentKeyNormalizer end Filter->>Checker : IsGrantAsync() Checker->>Lock : TryAcquireAsync() alt 获取锁成功 Lock-->>Checker : 返回锁句柄 Checker-->>Filter : 返回成功结果 Filter->>Client : 执行动作 else Lock-->>Checker : 返回null Checker-->>Filter : 返回失败结果 Filter->>Filter : WrapGrantException() Filter-->>Client : 返回429错误 end else Filter->>Client : 直接执行动作 end ``` **Diagram sources ** - [AbpIdempotentActionFilter.cs](file://aspnet-core/framework/mvc/LINGYUN.Abp.AspNetCore.Mvc.Idempotent/LINGYUN/Abp/AspNetCore/Mvc/Idempotent/AbpIdempotentActionFilter.cs) - [AbpAspNetCoreMvcIdempotentModule.cs](file://aspnet-core/framework/mvc/LINGYUN.Abp.AspNetCore.Mvc.Idempotent/LINGYUN/Abp/AspNetCore/Mvc/Idempotent/AbpAspNetCoreMvcIdempotentModule.cs) **Section sources** - [AbpIdempotentActionFilter.cs](file://aspnet-core/framework/mvc/LINGYUN.Abp.AspNetCore.Mvc.Idempotent/LINGYUN/Abp/AspNetCore/Mvc/Idempotent/AbpIdempotentActionFilter.cs) ### 拦截器注册器 (IdempotentInterceptorRegistrar) `IdempotentInterceptorRegistrar`负责在服务注册时自动为符合条件的服务添加幂等性拦截器。它通过检查服务类型是否实现特定接口或方法是否有`Idempotent`属性来决定是否应用拦截。 ```mermaid flowchart TD A[服务注册] --> B[IdempotentInterceptorRegistrar] B --> C{ShouldIntercept?} C --> |是| D[添加IdempotentInterceptor] C --> |否| E[不添加拦截器] D --> F[服务包含幂等性拦截] E --> G[服务无幂等性拦截] subgraph ShouldIntercept逻辑 C --> H{"类型不是忽略类型?"} H --> |否| I[返回false] H --> |是| J{"实现ICreateAppService?"} J --> |是| K[返回true] J --> |否| L{"实现IUpdateAppService?"} L --> |是| K L --> |否| M{"实现IDeleteAppService?"} M --> |是| K M --> |否| N{AnyMethodHasIdempotentAttribute?} N --> |是| K N --> |否| I end ``` **Diagram sources ** - [IdempotentInterceptorRegistrar.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentInterceptorRegistrar.cs) - [IdempotentInterceptor.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentInterceptor.cs) **Section sources** - [IdempotentInterceptorRegistrar.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentInterceptorRegistrar.cs) ## 配置方式 ### 全局配置 幂等性模块通过`AbpIdempotentOptions`类提供全局配置选项,可以在模块的`ConfigureServices`方法中进行配置。 ```mermaid classDiagram class AbpIdempotentOptions { +bool IsEnabled +int DefaultTimeout +string IdempotentTokenName +int HttpStatusCode +AbpIdempotentOptions() } note right of AbpIdempotentOptions 默认值 : - IsEnabled : false - DefaultTimeout : 5000 (5秒) - IdempotentTokenName : X-With-Idempotent-Token - HttpStatusCode : 429 (Too Many Requests) end ``` **Diagram sources ** - [AbpIdempotentOptions.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/AbpIdempotentOptions.cs) **Section sources** - [AbpIdempotentOptions.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/AbpIdempotentOptions.cs) ### MVC特定配置 `AbpAspNetCoreMvcIdempotentOptions`提供了MVC特定的配置,主要用于控制哪些HTTP方法需要进行幂等性检查。 ```mermaid classDiagram class AbpAspNetCoreMvcIdempotentOptions { +List SupportedMethods +AbpAspNetCoreMvcIdempotentOptions() } note right of AbpAspNetCoreMvcIdempotentOptions 默认支持的方法 : - POST - PUT - PATCH DELETE方法默认不支持 end ``` **Diagram sources ** - [AbpAspNetCoreMvcIdempotentOptions.cs](file://aspnet-core/framework/mvc/LINGYUN.Abp.AspNetCore.Mvc.Idempotent/LINGYUN/Abp/AspNetCore/Mvc/Idempotent/AbpAspNetCoreMvcIdempotentOptions.cs) **Section sources** - [AbpAspNetCoreMvcIdempotentOptions.cs](file://aspnet-core/framework/mvc/LINGYUN.Abp.AspNetCore.Mvc.Idempotent/LINGYUN/Abp/AspNetCore/Mvc/Idempotent/AbpAspNetCoreMvcIdempotentOptions.cs) ### 模块依赖配置 要使用幂等性功能,需要在模块上添加相应的依赖。 ```mermaid classDiagram class AbpIdempotentModule { <> +PreConfigureServices() +ConfigureServices() } class AbpAspNetCoreMvcIdempotentModule { <> +ConfigureServices() } class AbpAspNetCoreMvcIdempotentWrapperModule { <> } AbpAspNetCoreMvcIdempotentModule --> AbpIdempotentModule : "依赖" AbpAspNetCoreMvcIdempotentWrapperModule --> AbpAspNetCoreMvcIdempotentModule : "依赖" AbpAspNetCoreMvcIdempotentWrapperModule --> AbpAspNetCoreWrapperModule : "依赖" ``` **Diagram sources ** - [AbpIdempotentModule.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/AbpIdempotentModule.cs) - [AbpAspNetCoreMvcIdempotentModule.cs](file://aspnet-core/framework/mvc/LINGYUN.Abp.AspNetCore.Mvc.Idempotent/LINGYUN/Abp/AspNetCore/Mvc/Idempotent/AbpAspNetCoreMvcIdempotentModule.cs) - [AbpAspNetCoreMvcIdempotentWrapperModule.cs](file://aspnet-core/framework/mvc/LINGYUN.Abp.AspNetCore.Mvc.Idempotent.Wrapper/LINGYUN/Abp/AspNetCore/Mvc/Idempotent/Wrapper/AbpAspNetCoreMvcIdempotentWrapperModule.cs) **Section sources** - [AbpIdempotentModule.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/AbpIdempotentModule.cs) ## 使用场景 ### 创建操作幂等性 在创建资源的场景中,幂等性可以防止用户重复提交表单导致创建多个相同资源。 ```mermaid sequenceDiagram participant User as "用户" participant Browser as "浏览器" participant API as "API服务" participant DB as "数据库" User->>Browser : 点击提交按钮 Browser->>API : POST /api/orders API->>API : 生成幂等键 API->>API : 检查分布式锁 alt 锁不存在 API->>DB : 创建订单 DB-->>API : 订单ID API-->>Browser : 201 Created Browser-->>User : 显示成功 else 锁已存在 API-->>Browser : 429 Too Many Requests Browser-->>User : 显示重复提交提示 end User->>Browser : 再次点击提交(误操作) Browser->>API : POST /api/orders API->>API : 检查分布式锁 API-->>Browser : 429 Too Many Requests Browser-->>User : 显示重复提交提示 ``` **Diagram sources ** - [IdempotentChecker.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentChecker.cs) - [AbpIdempotentActionFilter.cs](file://aspnet-core/framework/mvc/LINGYUN.Abp.AspNetCore.Mvc.Idempotent/LINGYUN/Abp/AspNetCore/Mvc/Idempotent/AbpIdempotentActionFilter.cs) ### 更新操作幂等性 在更新资源的场景中,幂等性可以确保多次更新请求只产生一次实际更新。 ```mermaid sequenceDiagram participant Client as "客户端" participant Service as "服务" participant Cache as "缓存" participant DB as "数据库" Client->>Service : PUT /api/orders/123 Service->>Service : 生成幂等键(order : 123 : update) Service->>Cache : SETNX order : 123 : update 1 EX 5 alt 设置成功 Cache-->>Service : OK Service->>DB : UPDATE orders SET ... DB-->>Service : 更新结果 Service-->>Client : 200 OK Service->>Cache : DEL order : 123 : update else 设置失败 Cache-->>Service : 0 Service-->>Client : 429 Too Many Requests end Client->>Service : 网络超时, 重试 Service->>Service : 检查幂等键 Service-->>Client : 429 Too Many Requests ``` **Diagram sources ** - [IdempotentChecker.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentChecker.cs) - [IdempotentKeyNormalizer.cs](file://aspnet-core/framework/common/LINGYUN.Abp.Idempotent/LINGYUN/Abp/Idempotent/IdempotentKeyNormalizer.cs) ### 分布式环境下的幂等性 在微服务架构中,幂等性确保跨服务调用的一致性。 ```mermaid graph TD A[前端服务] --> B[订单服务] B --> C[库存服务] C --> D[支付服务] subgraph "幂等性保障" B --> E[(Redis分布式锁)] C --> E D --> E end A -->|创建订单| B B -->|检查幂等键| E alt 锁不存在 E -->|获取锁| B B -->|扣