接口等幂处理

介绍

✅ 什么是等幂(Idempotency)?

等幂

无论这个操作被执行多少次,结果都是一样的,不会因为多次执行而产生副作用。

通俗一点说:“点一次和点一百次,效果是一样的。”

✅ 在接口中,什么是等幂操作?

在 Web / API 开发中,一个 等幂操作的接口,意味着客户端(用户、服务、浏览器)多次请求同一个接口,结果不变,也不会影响系统的状态或数据重复修改。

操作等幂性原因
GET /user/123✅ 是多次获取用户信息不改变任何东西
DELETE /user/123✅ 是删除一次和删除多次效果一样,用户都不存在
PUT /user/123 {name: “Tom”}✅ 是每次更新为相同数据,结果一样
POST /user❌ 否每次都会新建一个用户,重复多次会创建多个资源
•	PUT 是等幂的,因为它是“更新为某个状态”
•	POST 不是等幂的,因为它每次都是“创建新的资源”

✅ 为什么等幂很重要?

• 防止重复扣款、重复下单、重复删除等问题;

• 支持客户端/中间代理的自动重试;

• 提高系统容错能力。

✅ 如何实现接口等幂?

常见做法有:

  1. 幂等键(Idempotency Key):客户端每次请求都带上一个唯一 key,服务端缓存这个 key,避免重复处理。例如支付场景就常用这个机制。

  2. 根据业务设计逻辑保证幂等:比如数据库 INSERT 改为 UPSERT(存在则更新,不存在则插入)。

  3. 幂等性中间件 / 请求锁定机制:防止重复请求在短时间内被处理多次。

处理PUT的等幂

多次调用会修改 update_time、产生日志、触发 webhook、更新缓存等等副作用。

理论上:

• PUT /resource/123 的语义是:把这个资源更新成某个固定状态

• 所以连续多次执行 PUT(用相同数据),最终资源状态是一致的 —— 这是“等幂”。

实际上:

• 即使数据一样,每次 PUT 可能都会执行:

• 自动更新时间戳(update_time)

• 写数据库变更日志

• 写操作审计表

• 发送消息到 MQ

• 清理或更新缓存

➤ 这些副作用就

破坏了等幂性

👉 方式一:判断数据是否变更

if new_data != old_data:do_update()

• 如果数据一样,直接跳过写入、跳过更新时间戳等

• 这种方式最简单,适合“频繁重复 PUT”的场景。

👉 方式二:允许更新,但保持副作用幂等

• 比如:

• update_time 只在数据真正变更时更新;

• 日志、MQ 消息仅在内容变更时才触发;

• 或使用幂等锁 + 缓存处理。

👉 方式三:使用幂等 key(更适合 POST)

比如前端在 10s 内重试,带上幂等 key,服务端只处理一次。

✅ 针对 update_time 的建议做法:

def update_user(user_id, new_data):old_data = db.get_user(user_id)if new_data == old_data:return  # 数据没变,不做更新new_data["update_time"] = now()db.update_user(user_id, new_data)

幂等锁+缓存处理

这是用于更复杂、可能存在并发请求前端重复请求场景的策略。

📌 场景:

假设你的接口会被短时间内 多次调用(并发 or 重试)

PUT /order/123/status {"status": "paid"}

应该避免:

•	用户一不小心连点了 2 次;
•	前端接口设置了“自动重试机制”;
•	网关/中间层产生了重复调用。

✅ 解决方式:使用「幂等锁」

  1. 给每次请求生成一个幂等 key(比如前端传递一个唯一 idempotent-key);

  2. 使用缓存(Redis)记录这个 key 的处理状态

  3. 判断是否已经处理过,如果是,就跳过执行逻辑。

# 接收到请求
key = f"idempotent:{user_id}:{operation_id}"
if redis.exists(key):return "已处理,直接返回"# 设置锁,有效期60秒
redis.set(key, "processing", ex=60)try:# 执行更新操作db.update_order_status("paid")mq.send("order.paid")write_log("用户付款成功")
finally:redis.delete(key)

等幂锁流程

✅ 幂等锁的完整流程设计(前后端协作)

🔸 适用场景:

• 用户发起重要操作,如:下单、支付、扣积分、修改状态

• 你希望避免:

• 用户手抖点两下

• 前端接口自动重试

• 网关中转多次

• 并发执行相同逻辑导致“重复创建 / 重复扣款”

✅ 正确的幂等锁逻辑应该是:

✅ 「令牌模式」幂等方案

后端生成 幂等 key,前端持有这个 key,之后带着这个 key 去执行幂等请求。

模式说明适合场景
令牌模式前端先拿一个幂等 key(令牌),再带着 key 去调接口用户主动操作型,如“提交订单”
前端生成UUID前端自己生成 UUID,当做幂等 key 发请求自动重试 / 服务间调用 场景

令牌方式:

•	幂等 key 生命周期完全由后端掌控 ✅;
•	安全性高,不依赖前端生成 uuid 的正确性 ✅;
•	能配合业务类型(如创建订单、支付、退款)做细粒度控制 ✅;
•	可以直接缓存执行结果,实现「重复请求 → 直接返回结果」 ✅;
维度你说的方式(后端生成)之前的方式(前端生成)
控制权在后端 ✅在前端 ❌
安全性更高 ✅依赖前端或外部系统
结果缓存容易实现 ✅实现麻烦 ❌
实现复杂度多一步(key申请)略简单
应用场景提交表单、支付类接口微服务调用、幂等补偿逻辑

幂等令牌机制”,非常适合处理「用户主动操作 + 严格控制重复」的接口,强烈推荐在 支付、下单、扣款等业务中使用。

注意:

前端生成 UUID 并不是简单「纯随机」,它要遵循 可识别性可复用性 的规则,才能让后端识别同一个操作。

✅ 正确的前端 UUID 幂等 key 设计方案

🔸 前提场景适用:

• 后端不参与幂等 key 生成(例如微服务架构中,一些服务没有共享 Redis)

• 前端或调用方能控制 key 生成(如 App / 网关 / API 调用方)

• 通常用于:接口重试、任务去重、上传文件避免重复入库等

需要生成的 UUID 实际是“结构化唯一 key”,并不是完全随机,比如:

idempotent:<业务类型>:<用户ID>:<业务ID或时间戳>
业务场景幂等 key 示例
下单idemp:order:uid123:order456
修改用户信息idemp:user:update:uid123
提交问卷idemp:survey:uid123:survey_20240330
提交任务(时间窗口内)idemp:task:uid123:20240330T10
Key 设计是否推荐原因
完全随机 UUID❌ 不推荐后端无法判断是否是重复操作
带业务结构的 key✅ 推荐可以判断“是不是相同操作”
后端统一分发 key✅ 更推荐更安全、更集中控制

与其在前端搞业务 ID / 时间戳构造 key,不如直接用令牌机制:后端统一生成并下发幂等 key,前端拿着用。

对比点时间戳方案(前端方案)令牌机制(后端)
幂等 key 来源前端生成时间戳后端统一生成
是否真正幂等❌ 多次执行都不同✅ 同一个 key 保证只执行一次
是否能缓存结果❌ 难以复用✅ 可直接返回上次执行结果
实现复杂度中(要设计 key 格式)高一点(需要额外接口)
安全性 & 可控性❌ 前端失控✅ 后端控制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/75049.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P1090合并果子(优先队列)

洛谷题目 这里使用的是优先队列&#xff0c;非常简单 首先让我们一起来学习一下优先队列&#xff08;默认是从大到小来排列&#xff09; 首先要使用头文件 #include<queue> using namespace std; 然后声明有限队列 priority_queue<int> a; priority_queue&…

蓝桥杯备考---->并查集之 Lake Counting

这道题就统计有多少个连通块就行了 这时候我们又需要把二维转成一维了&#xff0c;也就是把每一个格子都给一个编号 当我们合并连通块的时候&#xff0c;其实是只需要四个方向的 因为我们是从上往下遍历的&#xff0c;我们遍历到某个位置的时候&#xff0c;它已经和上面部分…

React受控表单绑定

受控表单绑定 在 React 中&#xff0c;受控组件&#xff08;Controlled Component&#xff09;是指表单元素的值由 React 组件的 state 管理&#xff0c;React 通过 onChange 事件监听输入变化&#xff0c;并实时更新 state&#xff0c;从而控制表单输入值。 为什么要使用受控…

8、linux c 信号机制

一、信号概述 1. 信号概念 信号是一种在软件层次上对中断机制的模拟&#xff0c;是一种异步通信方式。信号的产生和处理都由操作系统内核完成&#xff0c;用于在进程之间传递信息或通知某些事件的发生。 2. 信号的产生 信号可以通过以下方式产生&#xff1a; 按键产生&…

CSP-J 2019 入门级 第一轮(初赛) 完善程序(2)

【题目】 CSP-J 2019 入门级 第一轮&#xff08;初赛&#xff09; 完善程序&#xff08;2&#xff09; &#xff08;计数排序&#xff09;计数排序是一个广泛使用的排序方法。下面的程序使用双关键字计数排序&#xff0c;将n对10000 以内的整数&#xff0c;从小到大排序。 例如…

Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档(带图片)预览,并导出

Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档&#xff08;带图片&#xff09;预览&#xff0c;并导出 预览安装插件示例代码项目目录结构截图实际效果截图 动态渲染 .docx 文档&#xff08;带图片&#xff09;&#xff0c;预览、导出安装插件docx 模板文件内容完整代码…

养老更安心!智绅科技“智慧”养老系统,智在何处?

在老龄化趋势不断加剧的当下&#xff0c;养老问题成为全社会关注的焦点。 人们对于养老服务的需求日益增长&#xff0c;不仅期望能够得到基本的生活照料&#xff0c;更渴望在安全、舒适、便捷的环境中安享晚年。 智绅科技的“智慧”养老系统应运而生&#xff0c;凭借其独特的…

MySQL 当中的锁

MySQL 当中的锁 文章目录 MySQL 当中的锁MySQL 中有哪些主要类型的锁&#xff1f;请简要说明MySQL 的全局锁有什么用&#xff1f;MySQL 的表级锁有哪些&#xff1f;作用是什么&#xff1f;元数据锁&#xff08;MetaData Lock&#xff0c;MDL&#xff09;意向锁&#xff08;Inte…

vue前端代码作业——待办事项

美化样式示意图&#xff1a; 后端IDEA代码示意图&#xff1a; 代码解释&#xff1a; 1. isAllChecked 计算属性的作用 isAllChecked 用于实现 “全选 / 全不选” 功能&#xff0c;它是一个 双向绑定 的计算属性&#xff08;因为 v-model 需要同时支持读取和设置值&#xff09…

Oracle数据库数据编程SQL<3.1 PL/SQL 匿名块 及 流程控制中的条件判断、循环、异常处理和随机函数应用>

PL/SQL部分 在SQL的基础上增加了一些过程化的控制语句。 过程化控制语句包括&#xff1a;类型定义、判断、循环、游标、异常处理&#xff08;例外处理&#xff09; 目录 PL/SQL匿名块 一、匿名块基本结构 1、匿名块由三个部分组成&#xff1a; 2、注意事项&#xff1a; …

DeepSeek详解:探索下一代语言模型

文章目录 前言一、什么是DeepSeek二、DeepSeek核心技术2.1 Transformer架构2.1.1 自注意力机制 (Self-Attention Mechanism)(a) 核心思想(b) 计算过程(c) 代码实现 2.1.2 多头注意力 (Multi-Head Attention)(a) 核心思想(b) 工作原理(c) 数学描述(d) 代码实现 2.1.3 位置编码 (…

Git Reset 命令详解与实用示例

文章目录 Git Reset 命令详解与实用示例git reset 主要选项git reset 示例1. 撤销最近一次提交&#xff08;但保留更改&#xff09;2. 撤销最近一次提交&#xff0c;并清除暂存区3. 彻底撤销提交&#xff0c;并丢弃所有更改4. 回退到特定的提交5. 取消暂存的文件 git reset 与 …

前端知识点---事件监听器里面的e.target跟this的区别,e.target在事件委托中的好处

文章目录 ✅ 相同点✅ 不同点✅ 总结区别e.target与事件委托之间的关系 在事件监听器中&#xff0c;e.target 和 this 有时是一样的&#xff0c;但它们并不完全相同。 ✅ 相同点 当事件直接绑定到元素时&#xff1a; e.target 和 this 通常指向相同的元素&#xff0c;即事件绑…

Elasticsearch 完全指南

1. Elasticsearch基础知识 1.1 什么是Elasticsearch Elasticsearch是一个基于Lucene的分布式、RESTful风格的搜索和数据分析引擎。它是一个开源的、高扩展的、分布式的全文搜索引擎,可以近乎实时地存储、检索数据。 Elasticsearch不仅仅是一个全文搜索引擎,它还可以用于以…

Python 3 与 MySQL 数据库连接:mysql-connector 模块详解

Python 3 与 MySQL 数据库连接&#xff1a;mysql-connector 模块详解 概述 在Python 3中&#xff0c;与MySQL数据库进行交互是一个常见的需求。mysql-connector是一个流行的Python模块&#xff0c;它提供了与MySQL数据库连接和交互的接口。本文将详细介绍mysql-connector模块…

SQL:CASE WHEN使用详解

文章目录 1. 数据转换与映射2. 动态条件筛选3. 多条件分组统计4. 数据排名与分级5. 处理空值与默认值6. 动态排序 CASE WHEN 语句在 SQL 中是一个非常强大且灵活的工具&#xff0c;除了常规的条件判断外&#xff0c;还有很多巧妙的用法&#xff0c;以下为你详细总结&#xff1a…

【字符设备驱动开发–IMX6ULL】(二)Linux 设备号

【字符设备驱动开发–IMX6ULL】&#xff08;二&#xff09;Linux 设备号 文章目录 【字符设备驱动开发–IMX6ULL】&#xff08;二&#xff09;Linux 设备号1 设备号的组成2.设备号的分配 1 设备号的组成 为了方便管理&#xff0c;Linux 中每个设备都有一个设备号&#xff0c;设…

【字符设备驱动开发–IMX6ULL】(一)简介

【字符设备驱动开发–IMX6ULL】&#xff08;一&#xff09;简介 一、Linux驱动与裸机开发区别 1.裸机驱动开发回顾 ​ 1、底层&#xff0c;跟寄存器打交道&#xff0c;有些MCU提供了库。 spi.c&#xff1a;主机驱动&#xff08;换成任何一个设备之后只需要调用此文件里面的…

YOLOv8+ Deepsort+Pyqt5车速检测系统

该系统通过YOLOv8进行高效的目标检测与分割&#xff0c;结合DeepSORT算法完成目标的实时跟踪&#xff0c;并利用GPU加速技术提升处理速度。系统支持模块化设计&#xff0c;可导入其他权重文件以适应不同场景需求&#xff0c;同时提供自定义配置选项&#xff0c;如显示标签和保存…

蓝桥杯嵌入式学习笔记

用博客来记录一下参加蓝桥杯嵌入式第十六届省赛的学习经历 工具环境准备cubemx配置外部高速时钟使能设置串口时钟配置项目配置 keil配置烧录方式注意代码规范头文件配置 模块ledcubemx配置keil代码实现点亮一只灯实现具体操作的灯&#xff0c;以及点亮还是熄灭 按键cubemx配置k…