如何在 Python 3 中重新编码 S3 密钥的 AWS Lambda 事件编码?

Dou*_*wer 7 amazon-s3 amazon-web-services python-3.x aws-lambda

我正在编写一个 python 3 AWS Lambda 例程,它将从 Lambda 事件对象获取 S3 存储桶和密钥 (source_key),并将文件复制到具有相同密钥值 (Destination_key) 的另一个 S3 存储桶。

但是,事件对象中的 S3 Key 的编码方式使得当我使用 source_key 值写入目标存储桶时,S3 会抛出 404 错误。

S3 Lambda 事件对象返回的密钥:

'object': {'key': 'SBN-Fwd_+USPS+-+Springdale%2C+OH+-+Mail+Processing+Facility+-+Bid+Extension+Notice.eml' 
Run Code Online (Sandbox Code Playgroud)

将“key”值提交回 S3 时出错:

{'Error': {'Code': 'NoSuchKey', 'Message': 'The specified key does not exist.', 'Key': 'SBN-Fwd_+USPS+-+Springdale%2C+OH+-+Mail+Processing+Facility+-+Bid+Extension+Notice.eml'}, 'ResponseMetadata': {'RequestId': '2C0154D58032B5B4', 'HostId': 'zxp56SHdODohW5ln8B5GOW+YPqGfL4/kJGD+qV46yMhLZU92BrOC/hlh/HPHywAuGuJiICL0RFk=', 'HTTPStatusCode': 404, 'HTTPHeaders': {'x-amz-request-id': '2C0154D58032B5B4', 'x-amz-id-2': 'zxp56SHdODohW5ln8B5GOW+YPqGfL4/kJGD+qV46yMhLZU92BrOC/hlh/HPHywAuGuJiICL0RFk=', 'content-type': 'application/xml', 'transfer-encoding': 'chunked', 'date': 'Thu, 20 Sep 2018 16:40:00 GMT', 'server': 'AmazonS3'}, 'RetryAttempts': 0}}
Run Code Online (Sandbox Code Playgroud)

我只是使用 boto3 将source_key 复制到destination_key,同时指定不同的存储桶。

 copy_source = {'Bucket': source_bucket, 'Key': source_key}
 destination_key = source_key

 s3resource.copy(copy_source ,destination_bucket, destination_key)
Run Code Online (Sandbox Code Playgroud)

只要 source_key 不包含任何奇怪的字符(空格、逗号等),此例程就可以完美运行

如何处理 source_key 以确保它与目标密钥兼容?我找不到任何有关 S3 期望编码的文档。

小智 9

事件消息中的 S3 键是 URL 编码的。来自AWS 文档

s3 键提供有关事件中涉及的存储桶和对象的信息。对象键名值是 URL 编码的。例如,“redflower.jpg”变为“red+flower.jpg”(Amazon S3 返回“application/x-www-form-urlencoded”作为响应中的内容类型)。

为了正确地重复使用存储桶和密钥,您需要对它们进行解码。在 Python (>= 3.5) 中,您可以使用unquote_plus

from urllib.parse import unquote_plus 

copy_source = {'Bucket': source_bucket, 'Key': source_key}
destination_bucket = unquote_plus(source_bucket, encoding='utf-8')
destination_key = unquote_plus(source_key, encoding='utf-8')

s3resource.copy(copy_source ,destination_bucket, destination_key)

Run Code Online (Sandbox Code Playgroud)