订单服务篇-使用Token机制解决接口幂等性

本文探讨了如何在订单服务中利用Token机制解决接口幂等性问题。详细介绍了在何处使用Token,以及Token的生成和验证过程,强调了验证过程的原子性,并提到了使用Lua脚本来确保这一特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<think>我们正在讨论如何通过token机制实现接口幂等性。根据引用内容,实现思路如下:1.服务端提供生成token接口,客户端在执行业务前先请求获取token。2.服务端生成token并存储在Redis中(设置一定的有效期),然后将token返回给客户端。 3.客户端调用业务接口时,将此token放入请求头中(如Authorization头)。4.服务端收到业务请求后,先检查请求头中是否有token,如果没有则直接返回错误。5.如果有token,则检查Redis中是否存在该token-如果存在,则删除Redis中的token,继续执行业务逻辑。-如果不存在,说明该请求已经处理过(可能是重复请求),直接返回重复操作的结果(如提示“请勿重复提交”)。 这种方法可以确保同一token只能被使用一次,从而保证接口幂等性。下面是一个简单的代码示例:**TokenService接口定义:** ```javapublic interfaceTokenService{//生成tokenString createToken();//校验tokenvoidcheckToken(HttpServletRequestrequest)throws Exception; }``` **TokenService实现类:**```java@Servicepublicclass TokenServiceImpl implementsTokenService{@Autowiredprivate RedisTemplate<String, String> redisTemplate;privatestatic finalString TOKEN_PREFIX ="TOKEN:";@Overridepublic StringcreateToken() {//生成一个唯一标识,这里使用UUIDStringtoken =UUID.randomUUID().toString().replace("-", "");//存入Redis,并设置过期时间(例如5分钟)redisTemplate.opsForValue().set(TOKEN_PREFIX +token,token,5, TimeUnit.MINUTES);return token;}@Overridepublic voidcheckToken(HttpServletRequestrequest)throws Exception{String token= request.getHeader("Authorization");if (StringUtils.isEmpty(token)) {thrownew Exception("请求头中未包含token信息");}//从Redis中删除token(原子操作:获取并删除)String key= TOKEN_PREFIX +token;BooleanisDeleted= redisTemplate.delete(key);if(isDeleted ==null ||!isDeleted){thrownew Exception("重复请求或token已失效");}} }``` **在业务接口使用:** ```java@RestControllerpublicclass BusinessController {@AutowiredprivateTokenServicetokenService;@PostMapping("/submit")public ResponseEntity<String> submitOrder(HttpServletRequest request) {try{//校验tokentokenService.checkToken(request);//执行业务逻辑//...returnResponseEntity.ok("操作成功");}catch (Exception e) {returnResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());}}} ```**注意事项:**-生成token接口需要开放给客户端调用,但要注意安全,避免被恶意获取大量token导致Redis存储压力。 -设置合理的token过期时间,避免无效token长期占用内存。 -删除token的操作必须是原子的(使用Redis的delete操作是原子的),确保在高并发下不会出现多个请求同时校验同一个token的情况。 -如果业务执行失败,可以考虑将token回滚(重新存入Redis),但这样会增加复杂性。通常建议客户端在业务失败后重新获取token再重试。这种方法适用于大多数需要防止重复提交的场景,如订单提交、支付请求等。§§相关问题§§1.如何防止token被恶意获取? 2.除了token机制,还有哪些常见的接口幂等性实现方式? 3.如果业务执行时间很长,如何保证token的有效性?</think>### 通过Token实现接口幂等性的方法 接口幂等性是指**同一请求多次执行的结果与单次执行结果一致**。使用Token机制实现幂等性的核心思路是:**服务端生成唯一Token,客户端在请求时携带该Token服务端校验Token有效性并执行原子性操作**。以下是具体实现步骤: #### 🔑 实现流程 1. **生成Token** - 服务端提供获取Token接口(如 `/api/token`) - 生成唯一标识(如UUID)并存入Redis,设置合理过期时间(如5分钟) ```java public String createToken() { String token = UUID.randomUUID().toString(); redisTemplate.opsForValue().set("TOKEN:" + token, token, 5, TimeUnit.MINUTES); return token; } ``` 2. **客户端携带Token** - 客户端调用业务接口时,将Token放入请求头(如 `Authorization: TOKEN_abcd1234`) 3. **服务端校验Token** - 从请求头提取Token - 执行原子性操作:检查Redis是否存在该Token并立即删除 ```java public void checkToken(HttpServletRequest request) throws Exception { String token = request.getHeader("Authorization"); if (token == null) throw new Exception("Missing token"); // 原子操作:检查并删除Token String redisKey = "TOKEN:" + token; Boolean deleted = redisTemplate.delete(redisKey); if (deleted == null || !deleted) { throw new Exception("Duplicate request"); } } ``` 4. **执行业务逻辑** - 仅当Token校验通过后才执行业务代码 - 返回结果给客户端 #### ⚠️ 关键注意事项 1. **原子性操作** 校验和删除Token必须是原子操作(Redis的 `delete` 命令是原子的),避免并发场景下多个请求同时通过校验。 2. **Token存储设计** - Redis Key格式:`TOKEN:{实际token值}` - 设置过期时间防止资源泄漏,例如: ```java redisTemplate.expire(redisKey, 5, TimeUnit.MINUTES); ``` 3. **网络重试处理** 客户端在收到超时响应时,应重新获取Token再发起请求(而非重复使用同一Token)。 4. **分布式环境适配** 所有服务节点连接同一个Redis集群,确保Token状态全局一致[^1][^3]。 #### 🌰 典型应用场景 - 支付订单提交 - 表单重复提交防护 - 库存扣减操作 - 消息队列消费去重 > **为什么这种方式能保证幂等性?** > 每个Token仅允许消费一次,重复请求会因Redis中无对应Token而被拦截。业务逻辑执行与Token校验解耦,无需修改核心业务代码[^2][^3]。 --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值