1 个不稳定版本
0.0.1 | 2022年12月16日 |
---|
#6 in #幂等
28KB
526 行
幂等资源操作
提供基于资源元数据验证的无状态幂等请求的一组函数
目标
- 无状态幂等。
- 通用,可与任何 HTTP 服务器框架或日期时间库一起使用。
- 可定制。
用法
在 docs.rs 中描述了此库如何实现幂等,使用此方法的 API 设计技巧,定制指南和常见用例的默认参数
lib.rs
:
基于 HTTP 条件头 和其他自定义头来实现基于资源验证的资源操作。
幂等是如何实现的?
通过使用条件头 If-None-Match
、If-Match
和 If-Unmodified-Since
来实现请求的幂等性,以避免常见的资源变更问题,如 丢失更新,并确保请求只被处理一次。
使用条件头,可以在重复请求的情况下保留服务器状态,尽管如此,遇到超时错误并重试的客户端在接收到预条件失败的响应时,无法轻易知道服务器是否已处理该请求。
Accept-Modified-Since
头
为了服务器和客户端达成共识,支持一个自定义头 Accept-Modified-Since
,验证请求是否可能是之前已修改资源的重试调用。如果条件头不匹配,此头可由客户端用于每个可能接受在之前 潜在 更新之后修改的资源请求。
用法
在客户端发出的每个请求中,应将Accept-Modified-Since
头设置为客户第一次发送请求的时间,以便在响应未到达的情况下,可以重新发送请求,其中Accept-Modified-Since
与第一次尝试相同。
第一次尝试时间为:2022年12月13日星期二 17:08:09
PUT /blog/post HTTP/1.1
If-Match: #82c8d70155524b43a5652e04ad27cadf~V0000000000000003
Accept-Modified-Since: 2022-12-13T17:08:09.141Z
...
超时或某些网络错误
HTTP/1.1 408 Request Timeout
Date: Tue, 13 Dec 2022 17:08:10 GMT
...
在一段时间后,使用与第一次尝试相同的Accept-Modified-Since头
重新尝试请求
PUT /blog/post HTTP/1.1
If-Match: #82c8d70155524b43a5652e04ad27cadf~V0000000000000003
Accept-Modified-Since: 2022-12-13T17:08:09.141Z
...
使用第一次尝试的日期使用Accept-Modified-Since
,服务器可以验证资源是否已被修改,返回成功响应。
安全性
然而,如果第一次请求未处理且对资源进行了并发更新,则重新使用Accept-Modified-Since
将导致服务器接受重试请求而未处理请求,并返回成功响应。
尽管头语义仍然保留,但如果请求必须保证被应用,则不推荐使用Accept-Modified-Since
。
创建资源
默认情况下,创建操作不是幂等的调用,但将这些规则应用于这些操作后,它们可以成为幂等的。例如,在Vec中推入值与在Set中插入值。
let mut vec = Vec::new();
vec.push(1);
vec.push(2);
vec.push(2);
assert_eq!(vec.len(), 3);
let mut set = HashSet::new();
set.insert(1);
set.insert(2);
set.insert(2);
assert_eq!(set.len(), 2);
根据此示例,为同一类型的所有资源使用唯一值可以使创建操作幂等。
因此,通过在客户端生成资源ID,可以保证重复多次时只产生一个资源。
ID冲突
使用客户端生成的ID创建资源可能会导致冲突。因此,始终验证是否存在具有相同ID的资源,这是由If-None-Match: *
头强制执行的。
然而,使用Accept-Modified-Since
,请求可能会误用该头以允许创建具有更大数据范围的资源。
PUT /blog/post HTTP/1.1
If-Match: #82c8d70155524b43a5652e04ad27cadf~V0000000000000003
Accept-Modified-Since: 2000-12-13T17:08:09.141Z
为了防止这种滥用,可以将Accept-Modified-Since
日期限制为请求创建时减去一些允许验证可能的重试的时间($time::now() - ACCEPT_MODIFIED_SINCE_DURATION_LIMIT
),从而限制可能具有ID冲突的资源范围。
为ACCEPT_MODIFIED_SINCE_DURATION_LIMIT
选择持续时间应考虑ID熵以及在整个持续时间内在整个系统中创建的资源数量。作为一个安全的配置,对于大多数用例,使用强UUID v4和24小时的持续时间应该是一个好的标准。
HTTP创建请求
在HTTP API中,有两种可能的实现创建语义的方法
- POST
- 带有If-None-Match的PUT
两者都需要在请求中传递资源ID以使其成为幂等的,但是为了优先考虑API端点的标准化,对于幂等调用,首选带有If-None-Match头的PUT,而对于非幂等调用,首选POST。