LambdaとAPI Gatewayを利用してS3のファイルをローカルPCにダウンロードする


ファイルが存在していること前提です。

DownloadFile.py
# Create instances.
s3 = boto3.resource('s3')
bucket = s3.Bucket(S3Bucket)
S3KeyPrefix = "{your/download/file}"

try:
    # file selected.
    basename = os.path.basename(S3KeyPrefix)
    ext = ""
    if (len(basename) > 0) and ('.' in basename):
        ext = basename.split('.')[-1]
    if (ext != ""):
        try:
            contentType = "application/octet-stream"
            if ext in ("jpg", "jpeg"):
                contentType = "image/jpeg"
            elif ext == "pdf":
                contentType = "application/pdf"
            elif ext == "mp3":
                contentType = "audio/mpeg"
            elif ext == "mp4":
                contentType = "video/mp4"

            tmpPath = "/tmp/" + basename
            bucket.download_file(Filename = tmpPath, Key = S3KeyPrefix)

            res = {
                "statusCode": 200,
                "headers": {
                    "Content-Type": contentType
                },
                "body": base64.b64encode(open(tmpPath, 'rb').read()).decode('utf-8'),
                "isBase64Encoded": True,
            }
            return res

        except Exception as e:
            print(e)
            return {
                'statusCode': 404,
                'body': str(e)
            }

API Gatewayの29秒問題とLambdaの15分問題の対策はしていません。

追記

なんてことはない、Lambdaでダウンロードさせることはない。証明書付きURLを発行して、それを踏ませればいい。

DownloadFile.py
import json
import boto3

def lambda_handler(event, context):
    S3Bucket = "{your-bucket}"
    try:
        path = event['queryStringParameters']['path']

        # Create instances.
        s3 = boto3.client('s3')

        ret = s3.generate_presigned_url(
            ClientMethod = 'get_object',
            Params = {'Bucket': S3Bucket, 'Key': path},
            ExpiresIn = 1 * 60 * 60,
            HttpMethod = 'GET')

        location = "window.location.href='" + ret + "'"
        html = "<html><head><meta charset='utf-8' /></head>"
        html += "<body onLoad=setTimeout(\"" + location + "\",1000)>"
        html += "<a href = '" + ret + "'>ダウンロード</a>"
        html += "</body></html>"
    except Exception as e:
        print(e)
        return {
            'statusCode': 403,
            'body': 'File Not Found or url expired.'
        }
    return {
        'statusCode': 200,
        'headers': {
            'Content-Type': 'text/html',
            'charset': 'utf-8'
        },
        'body': html
    }