我为此奋斗了几个小时,却没有找到解决方案。这是场景:
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函数中运行的。
我不知道为什么CopyObjectAsync失败。我曾尝试深入研究CopyObjectAsync的反汇编代码,但它的调用是如此间接,以至于我走得并不远。此时,我最好的猜测是这是CopyObjectAsync中的错误。
任何建议将不胜感激, 感谢您的阅读!
其他:我想明确地说,这可以从常规的AWSSDK库(CopyObjectAsync或CopyObject)运行,仅在Lambda环境中的Core 2.0异步调用CopyObjectAsync中失败。
答案 0 :(得分:1)
好的,所以我弄清楚了,这绝对是核心2.0 CopyObjectAsync()中的一个错误。这是场景:
我们使用的开头带有斜杠的键,例如'/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可以很好地处理这些特定键(我在非Core库中进行了测试,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上添加了斜杠?没有这些键,就无法使用。
这是完整的最终代码:
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;
}
}