amazon-s3 - AWS S3 CopyObjectAsync 失败, key 不存在,但获取/放置成功

标签 amazon-s3 aws-lambda

我为此奋斗了几个小时,但从未找到解决方案。场景如下:

var copyObjectRequest = new CopyObjectRequest
{
    SourceBucket  = s3Event.S3.Bucket.Name,
    SourceKey  = s3Event.S3.Object.Key,
    DestinationBucket  = OutputBucketName,
    DestinationKey  = s3Event.S3.Object.Key,
};

var deleteRequest = new DeleteObjectRequest
{
    BucketName = copyObjectRequest.SourceBucket,
    Key = copyObjectRequest.SourceKey,
};

await S3Client.CopyObjectAsync(copyObjectRequest);
await S3Client.DeleteObjectAsync(deleteRequest);

S3Client.CopyObjectAsync 抛出错误:“指定的键不存在。” (永远不会达到 S3Client.DeleteObjectAsync。)

但是,以下代码有效(对于相同的值):

var request = new GetObjectRequest
{
    BucketName = copyObjectRequest.SourceBucket,
    Key = copyObjectRequest.SourceKey,
};

var response = await S3Client.GetObjectAsync(request);
var tempPath = $"{Guid.NewGuid():D}";
await response.WriteResponseStreamToFileAsync(tempPath, false, CancellationToken.None);

var putRequest = new PutObjectRequest
{
    BucketName = copyObjectRequest.DestinationBucket,
    Key = copyObjectRequest.DestinationKey,
    FilePath = tempPath,
};

var putResponse = await S3Client.PutObjectAsync(putRequest);

if (putResponse.HttpStatusCode == HttpStatusCode.OK)
{
    var deleteRequest = new DeleteObjectRequest
    {
        BucketName = copyObjectRequest.SourceBucket,
        Key = copyObjectRequest.SourceKey,
    };

    await S3Client.DeleteObjectAsync(deleteRequest);
}

为简洁起见,我删除了几乎所有错误检查、日志记录等。但如果需要,我很乐意分享完整功能。

请注意,这是在使用 Core 2.0 的 C# Lambda 函数中运行的。

  • 我已经排除了安全性,因为第二组调用需要与 CopyObject 调用相同的权限(我相信)(如果我错了请纠正我)。
  • 毫无疑问,对象位于存储桶中,并且指定为第二组的键使用完全相同的结构。
  • 目标存储桶中不存在 key 。
  • 源和目标存储桶具有相同的权限。
  • key 中没有特殊字符(我测试过的样本 key 是“/US/ID/Teton/EC2ClientDemo.zip”和“testkey”)。
  • 我正在测试的文件很小(示例文件为 30Kb)。
  • 我已经在 CopyObjectRequest 中使用和不使用 CannedACL 值进行了尝试(我认为它不需要一个用于我的目的,它移动的所有文件都是私有(private)的)。
  • 我已验证所有存储桶都在同一区域 (USWest2)。

我不明白为什么 CopyObjectAsync 会失败。我已经尝试深入挖掘 CopyObjectAsync 的反汇编代码,但它的调用是如此间接,我没有深入了解。在这一点上,我最好的猜测是它是 CopyObjectAsync 中的错误。

如有任何建议,我们将不胜感激, 感谢阅读!

另外:我想明确指出,这适用于常规 AWSSDK 库(CopyObjectAsync 或 CopyObject),它仅在 Lambda 环境中的 Core 2.0 异步调用 CopyObjectAsync 中失败。

最佳答案

好的,所以我想通了,这绝对是核心 2.0 CopyObjectAsync() 中的错误。场景如下:

我们使用的 key 以斜杠开头,例如“/US/ID/Teton/EC2ClientDemo.zip”。当我打开 S3 日志记录(谢谢@Michael-sqlbot)时,我看到的是:

[13/Jul/2018:17:44:18 +0000] 34.221.84.59 arn:aws:sts::434371411556:assumed-role/LambdaFunctionCreation/TestFunction 489A5570C2E840AC REST.COPY.OBJECT_GET US/ID/Teton/EC2ClientDemo.zip - 404 NoSuchKey

如您所见,CopyObjectAsync() 函数在调用之前去掉了第一个斜杠。 Get、Put 和 Delete 可以很好地处理这些特定的键(我在非核心库中对此进行了测试,CopyObjectAsync() 的同步和异步版本也可以很好地处理这些键)。

我必须做的是修复它如下:

var copyObjectRequest = new CopyObjectRequest
{
    SourceBucket  = s3Event.S3.Bucket.Name,
    SourceKey  = "/" + s3Event.S3.Object.Key,
    DestinationBucket  = OutputBucketName,
    DestinationKey  = "/" + s3Event.S3.Object.Key,
    CannedACL = S3CannedACL.BucketOwnerFullControl,
};

请注意 SourceKey 和 DestinationKey 上添加的斜线?没有这些, key 就会被破坏。

这里是完整的最终代码:

var copyObjectRequest = new CopyObjectRequest
{
    SourceBucket = s3Event.S3.Bucket.Name,
    SourceKey = s3Event.S3.Object.Key,
    DestinationBucket = OutputBucketName,
    DestinationKey = s3Event.S3.Object.Key,
    CannedACL = S3CannedACL.BucketOwnerFullControl,
};

try
{
    await s3Client.CopyObjectAsync(copyObjectRequest);
}
catch (AmazonS3Exception ase) when (ase.Message.Contains("key does not exist"))
{
    try
    {
        // If this failed due to Key not found, then fix up the request for the CopyObjectAsync bug in the Core 2.0 library and try again.
        var patchedCopyObjectRequest = new CopyObjectRequest()
                                       {
                                           SourceBucket  = copyObjectRequest.SourceBucket,
                                           SourceKey  = "/" + copyObjectRequest.SourceKey,
                                           DestinationBucket  = copyObjectRequest.DestinationBucket,
                                           DestinationKey  = "/" + copyObjectRequest.DestinationKey,
                                           CannedACL = copyObjectRequest.CannedACL,
                                       };

        await s3Client.CopyObjectAsync(patchedCopyObjectRequest);
    }
    catch (AmazonS3Exception)
    {
        // Rethrow the initial exception, since we don't want a confusing message to contain the modified keys.
        throw ase;
    }
}

关于amazon-s3 - AWS S3 CopyObjectAsync 失败, key 不存在,但获取/放置成功,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51219182/

相关文章:

django - 在 S3 上提供媒体文件以供销售或

amazon-web-services - AWS : What can I use to run periodic tasks on RDS?

amazon-web-services - 我应该如何将 secret (RDS 密码)传递到 CloudFormation/SAM 创建的 Lambda 函数中?

amazon-web-services - 从一个 SQS 触发器触发多个 lambda 函数

java - 即使在 Eclipse 中执行 Maven 更新后也无法导入依赖项

go - S3 存储桶命名策略问题并尝试将 SDK 生成的请求发送到实现 S3 API 的 API

javascript - Angular:如何为图像创建自定义管道?

amazon-s3 - 亚马逊 S3 cli 工具?

amazon-web-services - 从 Amazon Glacier 恢复数据

node.js - 接收 TypeError : AWS. RDSDataService 不是构造函数