如何使用有条件写入来防止对象覆盖 - Amazon Simple Storage Service

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

通过有条件写入,可以向写入请求中添加一个额外的标头,以便向 S3 操作指定前提条件。这可以通过验证存储桶中尚不存在具有相同键名称的现有对象,来防止覆盖现有数据。有条件写入适用于针对通用存储桶和目录存储桶的 API 请求。

在将对象上传到 Amazon S3 时,请指定键名称。键名称是存储桶中对象的唯一且区分大小写的标识符。如果您在未受版本控制或已暂停版本控制的存储桶中上传具有相同键名称的对象,则该对象将被覆盖。在受版本控制的存储桶中,最近上传的对象将成为对象的当前版本。

有条件写入将在 WRITE 操作期间检查对象是否存在。如果在存储桶中找到相同的键名称,则 WRITE 操作将失败。使用有条件写入,可以让多个客户端写入同一个存储桶,而不会覆盖现有对象。

要执行有条件写入,您必须拥有 s3:PutObject 权限。此权限使调用方能够检查存储桶中是否存在对象。可以在 AWS SDK 中使用带有预签名 URL 的有条件写入。

注意

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

支持的 API

以下 S3 API 支持使用有条件写入:

可以使用以下标头来写入依赖于对象键名称的对象。有关对象键名称的信息,请参阅为 Amazon S3 对象命名

PutObject

  • If-None-Match — 仅当指定存储桶中不存在具有相同键名称的现有对象时,才上传对象。必须对此参数使用 *(星号)值。

以下 put-object 示例命令说明了如何使用 AWS CLI,通过 if-none-match 参数借助有条件写入标头上传对象。

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

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

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

有关此标头的更多信息,请参阅《Amazon Simple Storage Service API 参考》中的 PutObject

CompleteMultipartUpload

  • If-None-Match — 仅当指定存储桶中不存在具有相同键名称的现有对象时,才完成上传。必须对此参数使用 *(星号)值。

以下 complete-multipart-upload 示例命令说明了如何使用 AWS CLI,通过 if-none-match 参数借助有条件写入标头完成分段上传。

aws s3api complete-multipart-upload --multipart-upload file://mpustruct --bucket amzn-s3-demo-bucket --key dir-1/my_images.tar.bz2 --upload-id uploadID --if-none-match "*"

有关更多信息,请参阅 AWS CLI 命令参考 中的 complete-multipart-upload

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

有关此标头的更多信息,请参阅《Amazon Simple Storage Service API 参考》中的 CompleteMultipartUpload

有条件写入行为

有条件写入会针对存储桶中的现有对象进行评估。如果存储桶中不存在具有相同键名称的现有对象,则写入操作将成功并导致 200 响应。如果存在现有对象,则写入操作将失败并导致 412 Precondition Failed 响应。对于启用了版本控制的存储桶,作为有条件评估的一部分,S3 会检查是否存在同名的当前对象版本。如果当前没有同名的对象版本,或者当前对象版本是删除标记,则写入操作将成功。否则,它会导致写入操作失败和 412 Precondition Failed 响应。

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

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

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

412 前提条件失败响应

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

两个客户端写入具有相同键名称的项目的示例。一个客户端使用适用于 MPU 的 UploadPart,另一个客户端使用 PutObject 和有条件写入。之后启动的 CompleteMultipartUpload 操作会失败。
409 冲突响应

如果在有条件写入请求可以完成之前,删除请求获得成功,则 Amazon S3 为写入操作返回 409 Conflict 响应。这是因为更早启动的删除请求优先于有条件写入操作。考虑以下示例,其中存储桶中存在文件 puppy.txt。客户端 1 开始对另一个同样名为 puppy.txt 的文件进行分段上传,目的是通过有条件写入来完成分段上传。在上传过程中,客户端 2 从存储桶中删除 puppy.txt。当客户端 1 尝试通过有条件写入使用 CompleteMultipartUpload 来上传其自己的 puppy.txt 文件时,它将失败并导致 409 Conflict 响应。在这种情况下,您必须启动新的分段上传。

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

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