什么是接口幂等?
接口幂等就是无论客户端调用服务端接口发起多少次请求, 有且只有一次有效.
如何解决幂等问题呢?
1. 暴露获取幂等 token 接口, 且在此时存储 Redis,MySQL, 本地内存等 (可根据具体业务场景选择 token 存储方式)
- @Autowired
- private RedissonClient redissonClient;
- private String createToken(){
- return UUID.randomUUID().toString().replace("-","");
- }
- @GetMapping("/getLdempotentToken")
- public Response<String> getLdempotentToken(){
- RMapCache<String,String> rMapCache = redissonClient.getMapCache(LdempotentAspect.LDEMPOTENT_TONE);
- String token = createToken();
- rMapCache.put(token,token);
- return Response.ok(token);
- }
2. 客户端在请求接口前先获取幂等接口, 然后在请求接口前写入请求头中.
key | value |
---|---|
ldempotent_token | ba4b441e75f2449792fce5eb0ccfa2ab |
3. 利用 spring aop 技术代码需要处理幂等接口. 在执行接口之前验证客户端请求头中的幂等 token, 验证成功则删除 token, 验证失败则直接返回错误信息.
- @Target({
- ElementType.METHOD
- })
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface Ldempotent {
- }
- @Slf4j
- @Component
- @Aspect
- public class LdempotentAspect {
- public static final String LDEMPOTENT_TONE = "ldempotent_token";
- @Autowired
- private RedissonClient redissonClient;
- @Pointcut("@annotation(com.fast.family.framework.core.redis.ldempotent.Ldempotent)")
- public void pointcut(){}
- @Around("pointcut()")
- public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
- String token = Optional.ofNullable(webUtils.getRequestHeader(LDEMPOTENT_TONE))
- .orElseThrow(() -> new LdempotentException(ResponseCode.LDEMPOTENT_ERROR.getCode()
- ,ResponseCode.LDEMPOTENT_ERROR.getMsg()));
- RMapCache<String,String> rMapCache = redissonClient.getMapCache(LDEMPOTENT_TONE);
- Optional.ofNullable(rMapCache.get(token))
- .orElseThrow(() -> new LdempotentException(ResponseCode.LDEMPOTENT_ERROR.getCode()
- ,ResponseCode.LDEMPOTENT_ERROR.getMsg()));
- rMapCache.remove(rMapCache.get(token));//token 一次有效, 所以在验证完后需删除
- return proceedingJoinPoint.proceed();
- }
- }
那么按照上述步骤则可以保证接口幂等性 (这种方式除了可以处理接口幂等, 还能处理其他问题吗? 哈哈哈哈哈哈)
来源: https://juejin.im/post/5c738562e51d450b8f469858