如何使用有条件写入来防止对象覆盖 - Amazon Simple Storage Service
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

如何使用有条件写入来防止对象覆盖

通过使用有条件写入,可以向 WRITE 请求中添加一个额外的标头,以便为 Amazon S3 操作指定前提条件。要有条件地写入对象,请添加 HTTP If-None-MatchIf-Match 标头。

If-None-Match 标头通过验证存储桶中尚不存在具有相同键名称的对象,来防止覆盖现有数据。

或者,您可以在写入对象之前添加 If-Match 标头来检查对象的实体标签(ETag)。通过此标头,Amazon S3 将提供的 ETag 值与 S3 中对象的 ETag 值进行比较。如果 ETag 值不匹配,则操作会失败。

存储桶拥有者可以使用存储桶策略对上传的对象强制实施有条件写入。有关更多信息,请参阅 强制对 Amazon S3 存储桶实施有条件写入

注意

要使用有条件写入,必须通过 HTTPS(TLS)发出请求,或使用 Amazon 签名版本 4 对请求进行签名。

如何防止基于键名称的对象覆盖

在创建对象之前,可以使用 HTTP If-None-Match 有条件标头,根据其键名称检查指定存储桶中是否已存在该对象。在将对象上传到 Amazon S3 时,请指定键名称:存储桶中对象的唯一且区分大小写的标识符。在不使用 If-None-Match 标头时,如果您在未受版本控制或已暂停版本控制的存储桶中上传具有相同键名称的对象,则该对象将被覆盖。在受版本控制的存储桶中,最近上传的对象成为对象的当前版本。具有 HTTP If-None-Match 标头的有条件写入将在 WRITE 操作期间检查对象是否存在。如果在存储桶中找到相同的键名称,则操作失败。有关使用键名称的更多信息,请参阅为 Amazon S3 对象命名

要执行具有 HTTP If-None-Match 标头的有条件写入,您必须拥有 s3:PutObject 权限。这使调用方能够检查存储桶中是否存在对象。If-None-Match 标头需要 *(星号)值。

您可以将 If-None-Match 标头与以下 API 结合使用:

以下 put-object 示例命令尝试对键名称为 dir-1/my_images.tar.bz2 的对象执行有条件写入。

aws s3api put-object --bucket amzn-s3-demo-bucket --key dir-1/my_images.tar.bz2 --body my_images.tar.bz2 --if-none-match "*"

有关更多信息,请参阅 Amazon CLI 命令参考 中的 put-object

有关 Amazon CLI 的更多信息,请参阅《Amazon Command Line Interface 用户指南》中的什么是 Amazon Command Line Interface?

如果对象已更改,如何防止被覆盖

对象的 ETag 是该对象所特有的字符串,它反映了对象内容的变化。可以使用 If-Match 标头将 Amazon S3 存储桶中对象的 ETag 值与您在 WRITE 操作期间提供的值进行比较。如果 ETag 值不匹配,则操作会失败。有关 ETag 的更多信息,请参阅使用 Content-MD5 和 ETag 验证上传的对象

要执行具有 HTTP If-Match 标头的有条件写入,您必须拥有 s3:PutObjects3:GetObject 权限。这使调用方能够检查 ETag 并验证存储桶中对象的状态。If-Match 标头要求将 ETag 值作为字符串。

您可以将 If-Match 标头与以下 API 结合使用:

以下 put-object 示例命令尝试使用提供的 ETag 值 6805f2cfc46c0f04559748bb039d69ae 执行有条件写入。

aws s3api put-object --bucket amzn-s3-demo-bucket --key dir-1/my_images.tar.bz2 --body my_images.tar.bz2 --if-match "6805f2cfc46c0f04559748bb039d69ae"

有关更多信息,请参阅 Amazon CLI 命令参考 中的 put-object

有关 Amazon CLI 的更多信息,请参阅《Amazon Command Line Interface 用户指南》中的什么是 Amazon Command Line Interface?

有条件写入行为

具有 If-None-Match 标头的有条件写入

具有 If-None-Match 标头的有条件写入会针对存储桶中的现有对象进行评估。如果存储桶中不存在具有相同键名称的现有对象,则写入操作将成功并导致 200 OK 响应。如果存在现有对象,则写入操作将失败,并导致 412 Precondition Failed 响应。

对于启用了版本控制的存储桶,如果没有同名的当前对象版本,或者当前对象版本是删除标记,则写入操作将成功。否则,它会导致写入操作失败和 412 Precondition Failed 响应。

如果对同一个对象名称进行多个有条件写入,则第一个要完成的写入操作将成功。然后,Amazon S3 使后续写入失败并生成 412 Precondition Failed 响应。

如果在针对某个对象的有条件写入操作完成之前,对于该对象的删除请求获得成功,则在并发请求的情况下也可能收到 409 Conflict 响应。将有条件写入与 PutObject 结合使用时,可能会在收到 409 Conflict 错误后重试上传。使用 CompleteMultipartUpload 时,必须使用 CreateMultipartUpload 重新启动分段上传,以便在收到 409 Conflict 错误后再次上传对象。

具有 If-Match 标头的有条件写入

If-Match 标头会针对存储桶中的现有对象进行评估。如果存在具有相同键名称和匹配 ETag 的现有对象,则写入操作将成功并导致 200 OK 响应。如果 ETag 不匹配,则写入操作将失败并导致 412 Precondition Failed 响应。

如果是并发请求,您也可能收到 409 Conflict 响应。

如果在针对对象的有条件写入操作完成之前,对于对象的并发删除请求获得成功,您将收到 404 Not Found 响应,因为对象键不再存在。收到 404 Not Found 响应后,您应该重新上传对象。

如果没有同名的当前对象版本,或者当前对象版本是删除标记,则该操作失败并出现 404 Not Found 错误。

有条件写入场景

考虑以下场景,即两个客户端对同一个存储桶运行操作。

分段上传期间的有条件写入

有条件写入不考虑任何正在进行的分段上传请求,因为这些对象还不是完全写入的对象。请考虑以下示例,其中客户端 1 正在使用分段上传来上传对象。在分段上传期间,客户端 2 能够通过有条件写入操作成功写入相同的对象。随后,当客户端 1 尝试使用有条件写入完成分段上传时,上传将失败。

注意

这种情况将导致 If-None-MatchIf-Match 标头都得到 412 Precondition Failed 响应。

两个客户端写入具有相同键名称的项目的示例。一个客户端使用适用于 MPU 的 UploadPart,另一个客户端使用 PutObject 和有条件写入。之后启动的 CompleteMultipartUpload 操作会失败。
分段上传期间的并发删除

如果在有条件写入请求可以完成之前,删除请求获得成功,则 Amazon S3 为写入操作返回 409 Conflict404 Not Found 响应。这是因为更早启动的删除请求优先于有条件写入操作。在这种情况下,您必须启动新的分段上传。

注意

这种情况将对 If-None-Match 标头导致 409 Conflict 响应和对 If-Match 标头导致 404 Not Found 响应。

两个客户端的示例,一个客户端使用分段上传,另一个客户端在 MPU 启动后发送删除请求。删除请求在有条件写入开始之前完成。
注意

为了最大程度地降低存储成本,我们建议您配置生命周期规则,以便使用 AbortIncompleteMultipartUpload 操作在指定的天数后删除未完成的分段上传。有关创建生命周期规则以删除未完成的分段上传的更多信息,请参阅配置存储桶生命周期配置以删除未完成的分段上传