如何使用AWS Lambda(Python)接收文件

12

我正在尝试弄清楚如何通过Python的API调用接收浏览器发送的文件。

Web客户端可以发送任何类型的文件(比如.txt、.docx、.xlsx等)。我不知道是否应该使用二进制文件。

我的想法是将文件保存在S3上。现在我知道可以使用类似Aws Amplify的js库生成临时URL,但我对那个解决方案不太感兴趣。

非常感谢您提供任何帮助,我已经广泛搜索了Python的解决方案,但实际上找不到有效的解决方案!

我的API是私有的,我正在使用无服务器进行部署。

files_post:
  handler: post/post.post
  events:
    - http:
        path: files
        method: post
        cors: true
        authorizer: 
          name: authorizer
          arn: ${cf:lCognito.CognitoUserPoolMyUserPool}

编辑

我有一个半成品解决方案,可以处理文本文件,但无法处理 PDF、XLSX 或图像文件,如果有人能提供这样的解决方案,我会非常高兴。

from cgi import parse_header, parse_multipart
from io import BytesIO
import json


def post(event, context):


    print event['queryStringParameters']['filename']
    c_type, c_data = parse_header(event['headers']['content-type'])
    c_data['boundary'] = bytes(c_data['boundary']).encode("utf-8")

    body_file = BytesIO(bytes(event['body']).encode("utf-8"))
    form_data = parse_multipart(body_file, c_data)

    s3 = boto3.resource('s3')
    object = s3.Object('storage', event['queryStringParameters']['filename'])
    object.put(Body=form_data['upload'][0])

我尝试在一个zip文件上操作,但最终导致了存储桶中的zip文件损坏。 - user3821178
检查您的压缩过程,S3是可靠的,因此只有两个位置可能会出现问题:要么文件没有压缩好,要么传输不良。 - Tibo
1
我正在使用multipart/form-data进行发布,我能够获取其他表单字段,但是文件本身尽管在下载时得到更新,但我无法再打开它。 - user3821178
2个回答

1

这里有一个非常相似的问题在这里提出(并在评论中得到了回答)。

简短的答案是,为了避免CORS和防止文件损坏,您需要:

  1. 使用AWS SDK在S3中创建一个空对象
  2. 将该对象的预签名URL返回给前端
  3. 将文件PUT到该预签名URL

AWS实际上维护了一个非常好的示例来实现此场景的Go语言版本。

在Python中,一个简单的实现可能是这样的:

import boto3
import os
import csv

s3 = boto3.client('s3')

# Upload the empty file to S3
s3.put_object(Bucket='foobucket', Key='somekey', Body='')

# Generate a pre-signed URL for the empty file
url = s3.generate_presigned_url(
    ClientMethod='get_object',
    Params={
        'Bucket': 'foobucket',
        'Key': 'somekey'
    }
)

在Python缓冲区中,您可能需要使用io.BytesIO将文件转换为字节流,但是准备使用特定的Python库编写自定义逻辑以正确地将上传流式传输到缓冲区。

一旦您的文件被流式传输到缓冲区,只需使用Client.put_object方法:

s3.put_object(Bucket=bucket_name, Key=object_key, Body=buffer, ContentType='csv')

记得根据你的需求更改ContentType(本示例使用CSV格式)。


-1

您正在使用API Gateway,因此您的Lambda事件将映射到类似于以下内容(来自Amazon Docs):

{
    "resource": "Resource path",
    "path": "Path parameter",
    "httpMethod": "Incoming request's method name"
    "headers": {String containing incoming request headers}
    "multiValueHeaders": {List of strings containing incoming request headers}
    "queryStringParameters": {query string parameters }
    "multiValueQueryStringParameters": {List of query string parameters}
    "pathParameters":  {path parameters}
    "stageVariables": {Applicable stage variables}
    "requestContext": {Request context, including authorizer-returned key-value pairs}
    "body": "A JSON string of the request payload."
    "isBase64Encoded": "A boolean flag to indicate if the applicable request payload is Base64-encode"
}

您可以将文件作为base64值传递到请求体中,并在Lambda函数中进行解码。请参考以下Python代码片段:

def lambda_handler(event, context):
    data = json.loads(event['body'])
    # Let's say we user a regular <input type='file' name='uploaded_file'/>
    encoded_file = data['uploaded_file']
    decoded_file = base64.decodestring(encoded_file)
    # now save it to S3

1
我尝试了你的建议,但是出现了一个错误:无法解码JSON对象:ValueError 跟踪(最近的调用最先): 文件“/var/task/post/post2.py”,第16行,在post中 data = json.loads(event['body']) - Tibo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接