ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

同一个请求发两次:哪些会重复执行,哪些不会

同一个请求发两次:哪些会重复执行,哪些不会

授权与合规声明
本文全部操作对象均为自建隔离靶场(本机容器或隔离虚拟机),涉及安全测试的环节必须以取得合法授权为前提。未经授权的渗透测试违反《中华人民共和国网络安全法》与《刑法》相关条款,须承担相应法律责任。本文只讲环境配置、版本对照与靶场隔离,不含任何攻击步骤、利用载荷与绕过手法,请勿将文中环境指向任何非自有系统。

一、先把三个词分清:safe、幂等、可缓存

1.1 抖一下之后,两种完全相反的现场

线上常见的一幕:客户端把一个写请求发出去,等到超时也没等到响应,中间网络抖了一下。客户端里那段自动重发逻辑按设定把同一个请求又发了一遍。随后两种结果都可能出现。

第一种,列表里出现两条内容一样、时间只差几百毫秒的记录,立刻有人说这是重复提交,得加锁。第二种,列表里只有一条,于是有人得出另一个结论:这个接口是幂等的,POST 也能放心重发。

两个结论都下得太快。你看到一条还是两条,取决于服务端怎么处理这次请求,不取决于方法名。方法名给的是「客户端可以怎么假设」,不是「服务端一定怎么做」。这句话是本篇的地基。

1.2 三个词问的不是同一件事

safe、幂等、可缓存这三个词,经常被当成一组近义词混着用。它们回答的问题完全不同:

词它在问什么答错之后会出什么事谁最在意
safe这个方法的语义是不是本质上只读客户端会在用户没同意时发起带副作用的请求浏览器、爬虫、预取逻辑
幂等同一请求发多次,服务端被请求的效果是否和发一次相同断连之后不敢重发,或者不该重发时重发了客户端重试、网关、SDK
可缓存这个响应能否被中间层存下来复用缓存把不该复用的响应拿去复用了代理、CDN、浏览器缓存

三者有包含关系,但不是同一条线。safe 的方法一定幂等——这是 IDEM-02 的直接含义:PUT、DELETE 和所有 safe 方法都在幂等集合里;反过来,幂等的方法不一定 safe,PUT 和 DELETE 就是例子。可缓存和另外两个基本正交,它关心响应能不能被复用,不关心请求重复执行会怎样。

1.3 六个方法摆成一张矩阵

先把结论摊开,后面几章逐格解释:

方法safe幂等默认能否用缓存响应代替一句话
GET是是能取回表示,语义只读
HEAD是是能与 GET 同,但不带正文
OPTIONS是是一般不能问这个资源支持什么
TRACE是是一般不能回显收到的请求,诊断用
PUT否是不能用报文里的表示替换目标状态
DELETE否是不能解除 URI 映射与当前功能的关联
POST否否默认不能让目标资源按自己的语义处理
PATCH否否(请求可以做到)不能按补丁部分修改

第三列要说明一句:POST 那一格有本文唯一的逐字依据,就是 IDEM-07 里那句「a POST request cannot be satisfied by a cached POST response because POST is potentially unsafe」;其余几格按 RFC 9110 缓存一节的通行表述给出定位,本文不逐字引。PATCH 那格的括号,原因在 3.3 节。

本章可以带走的一句:safe 说的是「能不能不问就发」,幂等说的是「断了能不能再发」,可缓存说的是「响应能不能被别人拿去用」;三个问题,三套答案。

二、幂等说的是「效果」不是「响应」

2.1 定义句要一个词一个词读

RFC 9110 给幂等的定义只有一句,但每个成分都在限定范围:

「A request method is considered “idempotent” if the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request.」

拆开看:intended effect,不是 actual effect,规范约束的是请求打算达成的效果,不是这次执行实际发生了什么;on the server,效果落在服务端;multiple identical requests,前提是请求相同,同一个方法配不同报文,本来就不叫同一个请求;the same as the effect for a single such request,比的是多次和一次,不是两次和三次。

2.2 日志、修订历史、别的副作用,都不在射程内

紧接着的一句把边界划得更死:

「the idempotent property only applies to what has been requested by the user; a server is free to log each request separately, retain a revision control history, or implement other non-idempotent side effects for each idempotent request.」

这句话给了服务端很大的自由:每来一次请求就记一条日志、留一个修订版本、做一个别的非幂等副作用,都允许。前提只有一个——这些都不是用户请求的那件事。

回到开头那个场面,判断就清楚了。列表里多了一条业务记录,是被请求的效果重复了,不幂等;日志多两行、审计多两条、修订历史多一个版本,这些是服务端自己的记录,与幂等无关。计数器加了两则要看它是不是用户请求的那件事:用户点的是「点赞」,加两次就不幂等;计数器只是运维侧的访问统计,它属于附带记录。这一层只能由接口设计者自己判断。

2.3 三个层次分开看

层次幂等管不管典型例子判断依据
被请求的效果(资源状态)管记录被创建了几条、余额被扣了几次多次请求后的状态与一次是否相同
响应本身不管第一次 201、第二次 200;带不带 ETag定义句里没有响应这个词
服务端附带记录不管访问日志、审计流水、修订历史IDEM-03 明确说服务端可以自由做

IDEM-04 里还有半句正好印证第二行:「even if the original request succeeded, though the response might differ」——原请求可能已经成功了,尽管响应可能不同。

本章可以带走的一句:幂等约束的是「用户请求的那件事在服务端留下的状态」,不是响应长什么样,也不是服务端顺手记了几行日志。

三、逐方法过一遍

3.1 safe 的四个:GET、HEAD、OPTIONS、TRACE

「Request methods are considered “safe” if their defined semantics are essentially read-only」——注意 essentially 这个词,它说的是「本质上是只读的」,不是「绝对没有任何写入」。

一个 GET 让服务端写了行访问日志,它仍然 safe;刷了个缓存条目,通常也还是 safe。判据仍是第二章那条:这些写入是不是用户请求的那件事。四个里 GET、HEAD 日常用,OPTIONS 问资源支持什么,TRACE 回显请求用于诊断。

四个都 safe,按 IDEM-02 那句话,也都在幂等集合里。所以「GET 断了能不能重发」,答案是能。幂等集合比 safe 集合大,多出来的正是 PUT 和 DELETE。

3.2 PUT 与 DELETE:幂等,但都不是「没有后果」

「The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message content.」

两个动词:created、replaced。状态由报文里那份表示决定,不是在现有状态上叠一层。这就是 PUT 幂等的机制来源:同一份报文发一次和发五次,最终状态一样。

所以判断一个 PUT 接口是不是真幂等,不看它标了什么方法,看它内部做了什么。服务端要是把 PUT 实现成「把报文追加到列表末尾」,它已经不是在实现 PUT 的语义,幂等性也不成立。

DELETE 更容易被误解:

「requests that the origin server remove the association between the target resource and its current functionality. In effect, this method is similar to the “rm” command in UNIX: it expresses a deletion operation on the URI mapping of the origin server rather than an expectation that the previously associated information be deleted.」

第一句说的是解除 URI 映射与当前功能之间的关联;第二句补了关键的一笔:它表达的是对 URI 映射的删除操作,不是「之前关联的信息一定会被抹掉」。规范拿 rm 打比方——rm 一个文件,删掉的是目录里那条名字到 inode 的关联。

这就解释了 DELETE 为什么幂等:第一次删完,「目标资源已经不在那」成立;第二次再删,这个状态还是成立。响应可能从 204 变成 404,但那是响应层面的差异,按第二章的判据不算数。

3.3 POST 与 PATCH:一个不在集合里,一个要分两句读

POST 不在幂等集合里,规范在讲缓存时顺带把原因说清了:

「a POST request cannot be satisfied by a cached POST response because POST is potentially unsafe」

potentially unsafe,「可能不安全」。这个措辞不是「POST 一定写数据」,而是「规范不承诺 POST 的效果可以重复」。一个 POST 接口碰巧什么也没写,它仍然不在幂等集合里,因为规范给的是方法的默认假设。

PATCH 有两句话,必须一起读:

「PATCH is neither safe nor idempotent as defined by [RFC2616], Section 9.1.」

「A PATCH request can be issued in such a way as to be idempotent」

只读第一句,会得出 PATCH 不能重试;只读第二句,会得出 PATCH 可以重试。两句都对,说的是两件不同的事:方法层面不保证,具体请求可以做到。

差别在补丁的内容,不在方法名上。同样是 PATCH:「把这个字段设成这个值」,发几次结果一样,可以做到幂等;「把这个计数加一」,发几次加几次,不幂等。所以很多团队会在文档里给 PATCH 单独写一句「本接口幂等」或「不幂等」,而不是让调用方猜——文档给的是这一个接口的实际情况,那才是重试逻辑该看的。

下面是 PUT 一次往返的报文形状。本文没有在本机发出任何真实请求,这些是按规范形状写出来的示意,不是抓包结果,也不指向任何线上系统。

⚠️代码待验证(本机未发出请求,仅示意报文形状)

PUT /notes/42 HTTP/1.1 Host: notes.example.internal Content-Type: text/plain; charset=utf-8 Content-Length: 11 hello world HTTP/1.1 204 No Content

这个往返只能看出一件事:请求体带的是目标状态,响应体是空的。服务端到底替换了还是追加了,报文里看不出来。

本章可以带走的一句:方法名给的是默认假设,接口的真实幂等性由服务端的实现决定;PATCH 尤其要两句一起读,因为它把「方法不保证」和「请求可以做到」写在了同一段里。

四、为什么协议要在意这件事

4.1 断连之后的那一次自动重发

幂等不是为了好看才写进规范的,它解决的是一个很具体的工程问题:

「the request can be repeated automatically if a communication failure occurs before the client is able to read the server’s response」

注意时间点:before the client is able to read the server’s response。不是「请求失败之前」,是「客户端读到响应之前」。这个限定描述的正是那种「不知道服务端做没做」的状态。

规范接着举了 PUT 的例子:PUT 发出去之后连接断了,客户端可以换一条连接重发,「even if the original request succeeded, though the response might differ」。重发可能撞上一个已经成功的操作,但因为有幂等这个前提,撞上去不会多出一次效果。

连接怎么复用、持久连接什么时候断,不在本篇范围。本篇只关心:重发在语义上允不允许。

4.2 非幂等的纪律:SHOULD NOT 后面还有两个出口

「A client SHOULD NOT automatically retry a request with a non-idempotent method unless it has some means to know that the request semantics are actually idempotent, regardless of the method, or some means to detect that the original request was never applied.」

结构值得拆:主句是默认不许自动重试;出口一是「有办法知道这个请求的语义实际上是幂等的」,注意后面那个 regardless of the method,不管它标的是什么方法;出口二是「有办法检测到原请求从未被应用」。

出口一是本篇最容易被忽略的一句:方法名是默认值,不是天花板。一个 POST 接口如果被设计成幂等的,客户端在有依据的情况下重发是合规的。但依据必须是能说清的东西——文档写了、服务端有去重、或者调用方能查到操作状态。

出口二更实用:能检测到原请求从未被应用,就可以放心重发。比如请求根本没发出去,或者服务端能明确回答「这个操作我这儿没有」。

4.3 「结果未知」是最难的一格

客户端的处境有三种,不是两种:成功,拿到完整响应,服务端说做完了;明确失败,拿到完整响应,服务端说没做;结果未知,请求发出去了,响应没回来,或者回来了但不完整。

第三种最容易被当成第二种。「超时就当失败,走重试」这种写法对幂等的方法合理,对非幂等的方法就是把「可能已经做了」当成「肯定没做」。

⚠️代码待验证(本机未发出请求,以下为时刻示意,不是抓包)

t0 客户端发出请求 t1 服务端收到,开始处理 t2 服务端处理完成,效果已经落在状态里 t3 响应离开服务端 t4 客户端读到完整响应 断点落在 t0~t1 之间:请求没到,效果没发生 → 结果确定(没做) 断点落在 t1~t4 之间:效果可能已发生 → 结果未知 断点落在 t4 之后:客户端已读到 → 结果确定(做了)

从 t1 到 t4 这一整段,客户端看到的都是「没拿到响应」,但服务端的状态可能已经变了。重试决策的难点全在这一段里。

本章可以带走的一句:幂等不是给服务端省事的属性,它是给客户端一个「结果未知时可以重发」的许可;许可的边界由方法语义划定,不能靠「发一次试试」去试探。

五、重试决策的三层判据

5.1 第一层:方法在不在幂等集合里

第一层最省事,也最容易被跳过。拿到一个接口,第一个问题不是「它会不会失败」,而是「它标的是什么方法、默认在不在幂等集合里」。在集合内(GET、HEAD、OPTIONS、TRACE、PUT、DELETE),默认允许自动重发,但要过第二层和第三层;不在集合里(POST,以及没有特别设计过的 PATCH),默认不允许,除非能满足 4.2 节那两个出口之一。

5.2 第二层:失败落在哪一段

判据按断点位置分四档:

断点位置客户端看到什么服务端可能处于什么状态幂等方法非幂等方法
建连之前就失败请求一个字节都没发出去没收到可以重发可以重发(属「原请求从未被应用」)
请求已发出,响应头未收全只知道自己发过可能已执行可以重发默认不重发
响应头已收全,正文中断状态码已经读到已执行,结果已知可以重发按状态码判断
响应完整收到结果明确已执行按状态码按状态码

这张表是本文的归纳,条文依据只有两处:IDEM-04 那句「读到响应之前」,和 IDEM-05 那句「检测到原请求从未被应用」。其余格子是工程判断,用时按自己系统改。

5.3 第三层:响应码说的是「失败」还是「不知道」

  • 4xx:请求被理解了,但被拒绝。重发通常还是一样的结果,重试没有意义(少数与时间有关的除外)。
  • 408、429:明确要求「过一会儿再来」,是少数几个「重试被邀请」的状态码。
  • 5xx:服务端自认没做成。但 5xx 不等于「没产生效果」——写操作可能已经落库,然后在返回路径上出了问题。对非幂等的方法,5xx 仍属结果不确定。
  • 连接中断、超时:没有状态码,结果未知。

Retry-After就挂在这一层上。它的值可以是 HTTP-date,也可以是秒数;规范里delay-seconds = 1*DIGIT,是一个非负十进制整数。配在 503 上,表示服务预计要不可用多久;配在 3xx 上,表示两次请求之间至少要等多久。

⚠️代码待验证(本机未发出请求,仅示意响应形状)

HTTP/1.1 503 Service Unavailable Retry-After: 120 Content-Length: 0

同一个头也可以写成日期形式,形如Sun, 25 Oct 2026 06:30:00 GMT。两种都合法,只认秒数的代码遇上日期形式会当成没有这个头。

把三层串起来,判读顺序是这样:

⚠️代码待验证(本机未执行,仅记录判读顺序)

printf'%s\n''第 1 步:确认方法——它在不在幂等集合里'printf'%s\n''第 2 步:确认断点——请求发出去了没有,响应收到了多少'printf'%s\n''第 3 步:确认状态码——是明确失败,还是结果未知'printf'%s\n''第 4 步:三步都能给出答案才重发,任何一步含糊就先不重发'

本章可以带走的一句:重试不是「再发一次」,是「在三层判据都能给出答案时再发一次」;任何一层含糊,就先不发。

完整版对照资料:六个方法在 safe、幂等、可缓存三列上的完整对照,以及每个结论对应的 RFC 段落位置,都整理在这一份里。放在资料包里,扫码即可获取:

六、幂等键是怎么回事

6.1 先把身份说清:草案不是标准

有一个名字经常出现在接口文档里:Idempotency-Key(本文按待验证项处理)。截至 2026-10-25,业界确实有这类草案约定——IETF 有一份关于这个请求头的草案文档(draft-ietf-httpapi-idempotency-key-header),但它不是已发布的标准。

这个区别在落地时要守住:它不是 RFC,不能当规范条文引;草案会改,字段名、位置、服务端回应方式,不同版本之间可能不一样。本文只写到「业内有这类草案约定」这一层,不展开字段的具体语义。

6.2 服务端自己兜的三种做法

草案管不到的地方,得靠服务端自己。常见的有三种,都不依赖任何特定标准。

第一种,唯一约束。把「这是哪一次操作」落成一个标识,给标识建唯一索引。第二次带着同一个标识来,插入冲突,服务端就知道这件事做过了,把第一次的结果返回去。判断点在最底层,不易被上层绕过。

第二种,状态机。先把操作落成一条「待处理」记录,再推进到「已完成」。重复请求进来时先查:没有就新建并执行;有且未完成就等,或者返回当前状态;有且已完成就直接返回结果。好处是能区分「正在做」和「做完了」。

第三种,幂等重写。不改基础设施,改接口语义:把「加一」改成「设成某个值」,和 PUT 是同一个思路。代价是有些场景改不了,比如「每次调用都要新增一条流水」,本质上就是要多次效果。

做法能兜住什么兜不住什么
唯一约束同一个标识的重复插入同一标识下内容不同的冲突
状态机重复执行,以及「正在执行中」的并发状态推进那一步本身失败的情况
幂等重写语义层面的重复天生要求「每次都有新效果」的需求

6.3 三个边界:窗口、作用域、清理

窗口。去重记录留多久?留一天,第二天带同一个标识来就是新操作;留一年,存储成本和冲突概率都要重新算。窗口多长,等于定义了「多长时间内的重试算同一次」。

作用域。标识按客户端算、按账号算、还是按接口算?范围划小了,换个入口进来的重试就兜不住;范围划大了,两个不相干的操作可能撞在一起,被误判成重复。

清理。失败的那一次要不要留记录?失败就删掉,重试进来会当成新操作重新执行——对幂等的方法没问题,对非幂等的方法等于没兜。留着,又得能区分「失败但可以重试」和「失败且不该重试」。

⚠️代码待验证(示意,非真实实现)

收到请求,带着一个操作标识 ├─ 标识不存在 → 新建记录(待处理)→ 执行 → 标记完成 → 返回结果 ├─ 标识存在,未完成 → 不重复执行,返回当前状态(或让调用方稍后再来) ├─ 标识存在,已完成 → 不重复执行,返回第一次的结果 └─ 标识存在,内容不同 → 冲突,显式报错,不能当成功

本章可以带走的一句:幂等键是「让服务端认出这是同一次操作」的记号,不是「让请求自动变幂等」的魔法;认不出来的那部分,仍然要靠接口自己的语义来兜。

七、给接口写一份「重试友好度」自查

7.1 七个问题

给一个接口做重试友好度评估,问七个问题就够了,顺序不要换:

  1. 这个接口标的是什么方法?默认在不在幂等集合里?
  2. 如果不在,服务端做了什么让它实际上幂等?这对应 IDEM-05 的第一个出口。
  3. 客户端有没有办法检测「原请求从未被应用」?这对应第二个出口。
  4. 失败落在哪一段?能不能区分「没发出去」和「发出去了没回音」?
  5. 5xx 的时候,服务端能不能保证「要么全做,要么全不做」?
  6. 有没有Retry-After?给的是秒数还是 HTTP-date?
  7. 去重窗口多长、作用域多大、失败记录怎么清理?

7.2 三个「以为幂等其实不幂等」的写法

写法一:方法名对,实现不对。标了 PUT,内部却把报文追加到列表里。这种接口在文档上看着完全合规,实际每重发一次就多一条。

写法二:唯一约束建了,冲突时返回 500。服务端确实挡住了重复;客户端拿到的却是一次失败,分不清「已经做过了」和「真的做失败了」。前者该当成功,后者该排查。冲突时返回的应该是能表达「这件事已经完成」的结果。

写法三:去重键用请求体的哈希,而请求体里带了时间戳。每次生成的内容都不一样,哈希自然不一样,去重永远命不中。这种问题在联调阶段很难发现,因为正常流程下确实只有一次请求。

三个写法的共同点是:幂等性是在实现里成立的,不是在校验里成立的。方法名和文档都只是声明,能不能扛住重发,要看服务端真的做了什么。

7.3 落地顺序

  1. 先判方法,把接口按「默认可重发」「默认不可重发」分两堆。
  2. 再补服务端兜底:不可重发的那堆里,值得补的补唯一约束或状态机;不值得补的,在文档里写清楚,让调用方别猜。
  3. 最后才打开客户端的自动重试。顺序反了,等于拿真实流量做实验。

把七个问题收成一张表:

自查问题合格的样子不合格的信号
方法在幂等集合里吗方法与语义一致标了 PUT,实现是追加
不在集合里有兜底吗唯一约束或状态机,冲突时能表达「已完成」冲突时返回笼统失败
能检测「从未被应用」吗能查到操作是否存在只有「成功」和「失败」两种回答
失败阶段能区分吗能区分没发出、发出没回音、收到不完整一律按超时处理
5xx 时的原子性要么全做要么全不做部分完成,且没有标记
有没有 Retry-After有,且形式明确(秒数或日期)让调用方自己猜间隔
去重窗口与作用域有明确数值和范围说不清留多久、按什么算

本章可以带走的一句:重试友好度不是文档里的一句「本接口幂等」,是方法、实现、状态码、去重窗口四样东西对得上;对不上的地方,就是将来重复数据长出来的地方。

完整版对照资料:这份自查表连同判断依据的原文段落,做成了可以逐项打勾的版本。放在资料包里,扫码即可获取:

附表 A:本文引用事实与官方出处对照表

序号事实出处核验日期本文位置
1幂等定义:多次相同请求对服务端的 intended effect 与一次相同RFC 9110 §9.2.2(IDEM-01)2026-10-25第二章 2.1
2PUT、DELETE 与 safe 方法属于幂等集合RFC 9110 §9.2.2(IDEM-02)2026-10-25第一章 1.2
3幂等只约束被请求的效果,服务端可自由记日志、留修订历史RFC 9110 §9.2.2(IDEM-03)2026-10-25第二章 2.2
4通信失败发生在读到响应之前时,请求可被自动重发RFC 9110 §9.2.2(IDEM-04)2026-10-25第四章 4.1
5重发可能撞上已成功的原请求,「though the response might differ」RFC 9110 §9.2.2(IDEM-04)2026-10-25第二章 2.3
6非幂等方法默认不得自动重试,及其两个例外RFC 9110 §9.2.2(IDEM-05)2026-10-25第四章 4.2
7safe 的定义;GET、HEAD、OPTIONS、TRACE 为 safeRFC 9110 §9.2.1(IDEM-06)2026-10-25第三章 3.1
8幂等集合比 safe 集合大:PUT、DELETE 幂等但不 safeRFC 9110 §9.2.2(IDEM-06)2026-10-25第一章 1.2
9POST 是 potentially unsafe,不能被缓存的 POST 响应满足RFC 9110 §9.3.3(IDEM-07)2026-10-25第三章 3.3
10PUT 的语义:把目标资源状态创建或替换为报文表示定义的状态RFC 9110 §9.3.4(IDEM-08)2026-10-25第三章 3.2
11DELETE 的语义:解除 URI 映射与当前功能的关联,类比 rmRFC 9110 §9.3.5(IDEM-09)2026-10-25第三章 3.2
12PATCH 既不 safe 也不幂等RFC 5789 §2(IDEM-10)2026-10-25第三章 3.3
13「A PATCH request can be issued in such a way as to be idempotent」RFC 5789 §2(IDEM-10)2026-10-25第三章 3.3
14Retry-After的值可以是 HTTP-date 或秒数RFC 9110 §10.2.3(IDEM-11)2026-10-25第五章 5.3
15delay-seconds = 1*DIGIT,为非负十进制整数RFC 9110 §10.2.3(IDEM-11)2026-10-25第五章 5.3
16Retry-After配 503 表示服务预计不可用多久RFC 9110 §10.2.3(IDEM-11)2026-10-25第五章 5.3
17Retry-After配 3xx 表示两次请求之间至少等多久RFC 9110 §10.2.3(IDEM-11)2026-10-25第五章 5.3
18重试判据三层(方法 / 失败阶段 / 响应码)为本文归纳本文归纳(依据 IDEM-12)2026-10-25第五章 5.1 至 5.3
19失败阶段与能否重发的对应表为工程归纳,非规范原文本文归纳(IDEM-04、IDEM-05)2026-10-25第五章 5.2
20待验证:Idempotency-Key是 IETF 草案,不是已发布标准draft-ietf-httpapi-idempotency-key-header(IDEM-13)2026-10-25第六章 6.1
21本文未在本机发出任何 HTTP 请求,报文块均为示意本批纪律2026-10-25第三章 3.3
22不指向任何真实业务接口;本批纪律列明不写的内容全文未涉及本批纪律(IDEM-14)2026-10-25全文
23连接复用与持久连接不在本篇范围本批纪律2026-10-25第四章 4.1

附表 B:术语速查表

术语一句话解释
safe方法的定义语义本质上只读;GET、HEAD、OPTIONS、TRACE 属此类
幂等同一请求发多次,服务端被请求的效果与发一次相同;不比响应
intended effect请求打算达成的效果,幂等定义里用的就是这个词
结果未知请求已发出、响应未完整收到,服务端可能已执行
幂等键让服务端认出「这是同一次操作」的标记,相关草案尚未成为标准
幂等重写把「加一」这类非幂等操作改写成「设成某个值」
Retry-After告诉调用方多久之后再来;值可以是秒数或 HTTP-date
potentially unsafe规范对 POST 的定性,意思是效果不承诺可重复
去重窗口服务端保留操作记录的时长,超出窗口的重试算新操作
三层判据方法、失败阶段、响应码;三者都能给出答案才允许重发

写在最后:这篇用到的资料

写这篇文章时,我把 RFC 9110 里讲方法语义的那几段和 RFC 5789 里 PATCH 那一节对着读了很多遍,最费劲的是把「响应不一样」和「效果不一样」这两件事彻底分开,顺手也整理了几份配套的东西:

  • 靶场环境对照表:DVWA、upload-labs 在 Windows / macOS / Linux 三平台的可行性与推荐路径
  • Web 安全学习路线图:从基础打牢到安全管理,四个阶段各学什么
  • 常用靶场清单:每个靶场练什么、适合哪个阶段

资料是我自己整理的,放在下面这个码上,扫码即可获取:

添加时备注「靶场」,优先通过。

拿到之后建议先看环境对照表那一份,再回头把自己项目里那几个带自动重试的接口,按第五章的三层判据过一遍。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进