#http #rest #web #幂等

no-std 幂等资源操作

提供基于资源元数据的无状态幂等请求的一组函数

1 个不稳定版本

0.0.1 2022年12月16日

#6 in #幂等

MIT 许可证

28KB
526

幂等资源操作

提供基于资源元数据验证的无状态幂等请求的一组函数

目标

  • 无状态幂等。
  • 通用,可与任何 HTTP 服务器框架或日期时间库一起使用。
  • 可定制。

用法

docs.rs 中描述了此库如何实现幂等,使用此方法的 API 设计技巧,定制指南和常见用例的默认参数


lib.rs:

基于 HTTP 条件头 和其他自定义头来实现基于资源验证的资源操作。

幂等是如何实现的?

通过使用条件头 If-None-MatchIf-MatchIf-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。

无运行时依赖