简体中文

开发者工具 · UUID 生成器

幂等密钥:使用客户端生成的 UUID 确保重试安全

· 为什么它很重要

uuid 密码学 浏览器 API

序列图,显示客户端发送相同的幂等性密钥两次并且服务器返回缓存的响应
原始 ToolAcre 矢量图

付款请求超时会让您不确定是否已完成。幂等密钥可让您安全地重试,CSPRNG 生成的 UUID 是自然密钥。这篇文章端到端地解释了该模式。

可能已向客户收取两次费用的超时 — 存在可修复的故障模式幂等键

付款请求期间的超时会给客户端和系统带来真正的不确定性。您的 HTTP 客户端放弃等待响应,但支付服务器可能在连接关闭或超时之前处理了交易。如果您重试同一请求,您可能会向客户收取两次费用。如果您不重试,付款将永远无法完成。支付系统陷入了一个不幸的中间地带:客户的钱可能消失了,可能明天到达,可能被困在处理队列中,或者可能根本没有离开帐户。这种模糊性对于金融体系来说是不可接受的。

幂等键如何工作 - 服务器将第一个响应存储在该键下并重放以进行重复

幂等键通过使重试安全且具有确定性,优雅地解决了这个问题。客户端为每个意图(付款、转账、收费)生成一个唯一的密钥,并将其包含在每个请求中。服务器处理支付,缓存该密钥下的响应并存储密钥和结果。如果相同的密钥在保留窗口内再次到达,服务器将重播缓存的响应,而不再次处理支付。客户可以放心地重试,因为他们知道完全相同的密钥始终会产生相同的结果,无论发送多少次。这种模式消除了歧义并使重试逻辑安全。

在第一次尝试之前生成 - 为什么密钥必须在请求离开之前存在并在重试时逐字重用

该模式比现代 HTTP 规范更古老,但在造成广泛的财务损失和客户因重复收费而投诉后,在支付领域获得了重要地位。每个支付 API 和许多 Web 服务 API 现在都支持幂等性密钥。 CSPRNG 生成的 UUID 是密钥的自然选择,因为它是不可猜测的、唯一的,无需客户端之间的任何协调,并且不需要服务器端分配或中央权限。客户端在第一次尝试之前生成它,在每次重试时逐字重用它,并且每次都会收到相同的响应。不需要服务器端状态来协调密钥生成。

为什么是随机的 UUID 而不是计数器或有效负载哈希 — 唯一性无需协调,并且不会在意图之间意外重用

该密钥必须在请求离开客户端之前存在,因为在重试时生成它太晚而无法确保幂等性。如果第一个请求成功并向客户收费,则重试时生成新密钥将掩盖问题并再次收费。客户端必须在第一次尝试之前提交密钥,将其存储在内存或持久存储中,并在需要超时或重试时重用同一密钥。对于手动 API 测试,ToolAcre 生成器生成密钥,您可以将其粘贴到curl 或 REST 客户端中,在多个请求之间复制和重用以测试幂等性行为。

范围和生命周期 — 每个操作、每个帐户的密钥以及服务器应记住它们的时间

为什么幂等键使用 UUID 而不是哈希或顺序计数器?请求有效负载的哈希值看起来很直观——相同的有效负载会获得相同的哈希值,从而获得相同的密钥。但哈希对于这种用例来说很弱,因为两个几乎相同的请求具有不同的金额、不同的接收者或不同的参数,会产生完全不同的哈希,从而产生单独的费用,这是正确的,但不能提供所需的所有保护。顺序计数器需要协调和分布式状态:如果两个客户端都在您的基础设施上生成基于计数器的密钥,则它们的计数器可能会发生冲突。 UUID 不需要中央权威,是不可猜测的,并且极不可能在整个互联网上随时发生偶然冲突。

工作示例 - 使用相同密钥的重试序列,显示客户端发送的内容和服务器每次返回的内容

服务器端实现将响应存储在键下,并在重复时返回缓存的响应。复杂性在于决定实际操作问题:记住一个密钥的保留期限多长时间,缓存大小要记住多少个密钥,锁定如何防止具有相同密钥的两个并发请求处理两次支付以及何时忘记密钥进行清理。这些是 UUID 生成器范围之外的存储和可靠性问题。客户端的工作是生成一个好的密钥并在重试时重复使用它;服务器的工作是正确且持久地实现缓存。

这不包括什么——实现该模式所需的服务器端存储和锁定,这是一个单独的设计

一个工作示例显示了实践中的典型序列。移动应用程序需要使用支持幂等性的 API 向朋友转账。在发送请求之前,应用程序使用其本地加密库生成一个 UUID 或从 ToolAcre 生成器中获取一个用于测试目的:3fa85f64-5717-4562-b3fc-2c963f66afa6。应用程序向 /transfers 发送一个 POST 请求,其中包含 JSON 主体和 HTTP 标头幂等密钥:3fa85f64-5717-4562-b3fc-2c963f66afa6。服务器处理传输,将 3fa85f64-5717-4562-b3fc-2c963f66afa6 → {status: "success", transferId: "xfer-12345"} 存储在其缓存中,并返回 200 响应和结果。

要点:一个意图,一个关键 — ToolAcre 生成器为您提供了一个由 CSPRNG 支持的 UUID,可在手动测试集成时用作关键

网络超时,客户端看不到第一次尝试的响应。应用程序使用相同的幂等性密钥重试相同的请求,而不生成新的 UUID。服务器识别其缓存中的密钥,找到缓存的响应并立即返回 {status: "success", transferId: "xfer-12345"} ,无需处理新的传输,也无需再次向客户收费。该操作是幂等的:每次重试都会产生相同的可观察结果。对于有效的测试, ToolAcre 生成器可以提供密钥;生成 UUID,将其包含在标头中,观察响应并使用相同的密钥重新发送以验证服务器正确实现缓存。