我为此奋斗了几个小时,但从未找到解决方案。场景如下:
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/