通知已创建S3对象后,无法将文件从S3下载到lambda

时间:2018-12-30 18:23:26

标签: amazon-s3 aws-lambda boto3

我已将SES配置为将一些电子邮件放入S3存储桶中,并设置S3触发器以在创建的对象上触发lambda函数。在lambda中,我需要解析和处理电子邮件。这是我的lambda(相关部分):

s3client = boto3.client('s3')
def lambda_handler(event, context):
    my_bucket = s3.Bucket(‘xxxxxxxx')
    my_key = event['Records'][0]['s3']['object']['key']
    filename = '/tmp/'+ my_key
    logger.info('Target file: ' + filename)
    s3client.download_file(my_bucket, my_key, filename)
#   Process email file

download_file引发异常:

expected string or bytes-like object: TypeError


Traceback (most recent call last):
File "/var/task/lambda_function.py", line 22, in lambda_handler
s3client.download_file(my_bucket, my_key, filename)

...

File "/var/runtime/botocore/handlers.py", line 217, in validate_bucket_name
if VALID_BUCKET.search(bucket) is None:
TypeError: expected string or bytes-like object

有什么想法吗?存储桶很好,存储桶中有对象。

2 个答案:

答案 0 :(得分:1)

该错误与存储区名称有关(代码中有一个奇怪的弯引号)。

recommended检索对象详细信息的方法是:

for record in event['Records']:
    bucket = record['s3']['bucket']['name']
    key = record['s3']['object']['key']
    ...
    s3_client.download_file(bucket, key, download_path)

答案 1 :(得分:0)

编辑:我的第一个答案可能是错误的,这是另一种尝试

可以找到引发异常的验证函数here

# From the S3 docs:
# The rules for bucket names in the US Standard region allow bucket names
# to be as long as 255 characters, and bucket names can contain any
# combination of uppercase letters, lowercase letters, numbers, periods
# (.), hyphens (-), and underscores (_).
VALID_BUCKET = re.compile(r'^[a-zA-Z0-9.\-_]{1,255}$')

# [I excluded unrelated code here]

def validate_bucket_name(params, **kwargs):
    if 'Bucket' not in params:
        return
    bucket = params['Bucket']
    if VALID_BUCKET.search(bucket) is None:
        error_msg = (
            'Invalid bucket name "%s": Bucket name must match '
            'the regex "%s"' % (bucket, VALID_BUCKET.pattern))
        raise ParamValidationError(report=error_msg)

boto3在后台使用S3Transfer下载管理器,然后使用download方法定义为follows

def download(self, bucket, key, fileobj, extra_args=None,
             subscribers=None):
    """Downloads a file from S3
    :type bucket: str
    :param bucket: The name of the bucket to download from
...

它期望bucket参数为字符串,并且您正在传递s3.Bucket(‘xxxxxxxx')对象,该对象可能不是字符串。

我尝试将存储桶名称作为字符串传递给download_file


评论中指出的古老且最有可能的错误答案

一些sample code in the Boto Documentation向我们展示了如何执行从S3进行的下载:

import boto3
import botocore

BUCKET_NAME = 'my-bucket' # replace with your bucket name
KEY = 'my_image_in_s3.jpg' # replace with your object key

s3 = boto3.resource('s3')

try:
    s3.Bucket(BUCKET_NAME).download_file(KEY, 'my_local_image.jpg')
except botocore.exceptions.ClientError as e:
    if e.response['Error']['Code'] == "404":
        print("The object does not exist.")
    else:
        raise

查看您的代码,好像您在以错误的方式调用download_file方法,看起来应该像这样-您需要在Bucket-Object上调用该方法:

s3client = boto3.client('s3')
def lambda_handler(event, context):
    my_bucket = s3.Bucket(‘xxxxxxxx')
    my_key = event['Records'][0]['s3']['object']['key']
    filename = '/tmp/'+ my_key
    logger.info('Target file: ' + filename)
    my_bucket.download_file(my_key, filename)
#   Process email file

重要的部分是my_bucket.download_file(my_key, filename)