首页 > 其他分享 >接口幂等性详解

接口幂等性详解

时间:2024-02-10 14:55:24浏览次数:29  
标签:请求 redis 接口 token 详解 服务端 客户端

概述

所谓接口幂等性就是:在特定场景下,同一条件的多次接口调用,保证操作只执行一次,如果接口没有保证幂等性,在以下场景就会产生问题

  • 前端重复提交:用户进行注册、创建个人信息等操作,由于网络抖动导致页面没有及时响应,用户认为没有成功而多次点击提交按钮,发生重复提交表单请求
  • 接口超时重试:提供外部系统调用的接口,因为网络抖动等原因执行成功但没能及时响应,外部系统发起重试,导致重复调用
  • 消息重复消费:使用消息中间件时,消费者手动 ack 确认消息被正常消费时,消费者突然断开连接,已经执行的消息会重新放回队列,被其他消费者重新消费

如何实现接口幂等性?

1. 防重 Token 令牌

具体流程如下:

  • 客户端获取 token,服务端将 token 保存在 redis 中,token 需保证全局唯一
  • 之后客户端发起请求时必须携带 token
  • 服务端校验 token,如果成功则执行业务,并删除 redis 中的 token,否则为重复操作,直接返回结果

这种方式需保证同一请求都携带同一 token,比如同一订单的支付操作都使用同一 token 请求。另外,在并发情况下,Redis 查找数据与删除需要保证原子性,可以使用或 Lua 脚本保证

2. 使用 Redis 实现

这种实现方式是基于 redis 的 setnx 命令实现的,作用是如果 key 不存在,将 key 赋值为 value 并返回 1,若 key 已存在,则不做操作并返回 0

具体流程如下:

  • 客户端请求服务端,将能代表这次请求的唯一标识以 setnx 的方式存入 redis,并根据业务设置相应的超时时间
  • 如果设置成功,代表是第一次请求,执行后续业务逻辑
  • 如果设置失败,代表已经执行过请求,直接返回

redis 是单线程的,所以不会有并发问题

3. 加锁实现

具体流程如下:

  • 客户端请求服务端,对能代表这次请求的唯一标识加锁,保证同一时刻同一请求只有一个能被执行
  • 服务端根据唯一标识判断是否第一次请求,比如查询数据库是否已存在该唯一标识的记录,或者该唯一标识对应记录状态是否为【已完成】
  • 如果是第一次请求,执行后续业务逻辑,否则直接返回

4. 幂等表

加锁会影响性能,我们可以建一张幂等表,为能代表这次请求的唯一标识建立唯一约束

具体流程如下:

  • 客户端请求服务端,服务端会将本次请求的信息插入幂等表
  • 因为有唯一约束,如果幂等表中不存在本次请求记录,则插入成功,执行后续业务逻辑,插入失败,则直接返回

使用这种方式,每次请求都会幂等表新建一条记录,为了避免表数据过大,可以定期进行清理,或者使用流水表来代替幂等表。使用插入而不是查询,也能有效避免并发问题

标签:请求,redis,接口,token,详解,服务端,客户端
From: https://www.cnblogs.com/Yee-Q/p/18012149

相关文章

  • dotnet 接口的扩展方法 logger
    AddLogging的使用services.AddLogging(logBuilder=>{logBuilder.AddConsole();});AddLogging的实现publicstaticIServiceCollectionAddLogging(thisIServiceCollectionservices,Action<ILoggingBuilder>configure){//...}实现ILoggingBuilder的AddCo......
  • 网络游戏协议测试(接口测试)的一些总结
    什么是游戏协议?协议是网络游戏前后端交互的实现方式。游戏中协议的收发过程是怎样的?当我们在进行游戏的时候,我们点击了某个按钮进行某一种游戏行为,这个时候,客户端会按照跟服务器约定好的一些规则,将我们的游戏行为对应的请求和参数通过网络封包发送给服务器,服务端在收到这个......
  • Node.js+Express+Koa2开发接口学习笔记(六)
    预防sql注入sql注入最原始、最简单的攻击,从有了web2.0就有了sql注入攻击攻击方式:输入一个sql片段,最终拼接成一段攻击代码预防措施:使用mysql的escape函数处理输入内容即可例如登录,访问http://localhost:8080/login.html正常情况下是输入正确的用户名和密码来进行登录,这个登......
  • Java break、continue 详解与数组深入解析:单维数组和多维数组详细教程
    JavaBreak和ContinueJavaBreak:break语句用于跳出循环或switch语句。在循环中使用break语句可以立即终止循环,并继续执行循环后面的代码。在switch语句中使用break语句可以跳出当前case,并继续执行下一个case。示例://循环示例for(inti=0;i<10;i++......
  • Express+Koa2开发接口学习笔记(五)
    日志介绍日志可以记录系统的日常和错误行为系统日志有2种类型:①访问日志accesslog(server端最重要的日志)②自定义日志(包括自定义事件、错误记录等)系统日志通常是写在一个文件中,而不是写进Mysql或者redis中。nodejs文件操作新建一个项目file-text在目录下创建test.js和data......
  • 10_TIM编码器接口
    TIM编码器接口编码器接口简介正交编码器旋转编码器简介编码器接口基本结构工作模式实例(均不反相)实例(TI1反相)编码器接口测速选择接口和定时器接线图代码Encoder.c#include"stm32f10x.h"//DeviceheadervoidEncoder_Init(void){......
  • 接口传送集合数据备份
    //请求路径Stringurl=address+"/priceFreightpriceController.do?outGetMaplist&chargeableWeight="+weight;//url=url+"&data="+jsonString;Gsongson=newGson();//List转String......
  • 编程新手必学:Java运算符详解
    编程新手必学:Java运算符详解编程,这种强大的艺术形式,给我们带来了无穷的可能性。就像数学中的加减乘除,程序设计中也有一种类似的工具:运算符。作为一种编程语言,Java提供了一系列的运算符来执行各种基础和复杂的操作。在本文中,我将尝试解释Java中的各种运算符,并提供一些代码示例来说......
  • 详解golang实现一个带时效的环形队列
    1.需求mysql执行时间超过100ms以上打warn日志,但是一分钟以内这种warn日志超过10条就需要告警。所以需求就是获得一分钟以内mysql的warn的个数。2.分析为什么使用环形队列而不使用slice?因为队列长度固定,所以可以一开始就分配好空间,不用自动扩容,环形的目的就是不用改变数组的值,只用移......
  • 如何基于 spdlog 在编译期提供类 logrus 的日志接口
    如何基于spdlog在编译期提供类logrus的日志接口实现见Github,代码简单,只有一个头文件。前提几年前看到戈君在知乎上的一篇文章,关于打印日志的一些经验总结;实践下来很受用,在golang里结构化日志和logrus非常契合,最常见的使用方式如下。logrus.WithField("addr","127.0......