首页 > 解决方案 > 如何使用 boto3 和 lambda 从 S3 存储桶中的 html 页面上传文件?

问题描述

我想将大于 10 MB 的文件从 html 页面上传到 S3。

我有html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Upload File to S3 Bucket</title>
  </head>
  <body>
    <h3>Upload File to S3 Bucket</h3>
    <form
      action=" https://4oss3kkck9.execute-api.us-east-1.amazonaws.com/api/uploadhtml"
      method="post"
      enctype="multipart/form-data"
    >
      <h1>Select File:</h1>
      <input type="file" name="file" />
      <input type="submit" name="submit" value="Upload" />
    </form>
  </body>
</html>

我有一个由 API 端点触发的 lambda 函数:

这是 Lambda:

import json
import base64
import boto3
import email
import logging
import botocore
from create_bucket import create_bucket

def lambda_handler(event, context):
    s3 = boto3.client('s3')
    buckets = s3.list_buckets()
    bucket_name = ""
    bucket_without_extension = "filetypewithoutextension"
    print("Received event: " + json.dumps(event))
    
        # decoding form-data into bytes
    post_data = base64.b64decode(event["body"])
        # fetching content-type
    try:
        content_type = event["headers"]["content-Type"]
    except:
        content_type = event["headers"]["content-type"]
        # concate Content-Type: with content_type from event
    ct = "Content-Type: "+content_type+"\n"
    
        # parsing message from bytes
    msg = email.message_from_bytes(ct.encode()+post_data)
    print(msg)
    
        # checking if the message is multipart
    print("Multipart check : ", msg.is_multipart())
        
        # if message is multipart
    if msg.is_multipart():
        multipart_content = {}
            # retrieving form-data
        for part in msg.get_payload():
                # checking if filename exist as a part of content-disposition header
            if part.get_filename():
                # fetching the filename
                file_name = part.get_filename()
                bucket_name = f"thisismycomplicatedbucketfiletype-{file_name.split('.')[-1]}"
            multipart_content[part.get_param("name", header="content-disposition")] = part.get_payload(decode=True)
                
        in_bucket = False    
        
        if len(file_name.split(".")) == 1 or file_name.split(".")[1] == "":
            s3.put_object(Bucket=bucket_without_extension, Key=file_name, Body=multipart_content["file"],
                             ServerSideEncryption="aws:kms")
            return {
                "statusCode": 200,
                "body": json.dumps("File uploaded successfully!")
            }
            
        for bucket in buckets["Buckets"]:
            if bucket_name in bucket["Name"]:
                s3.put_object(Bucket=bucket_name, Key=file_name, Body=multipart_content["file"],
                             ServerSideEncryption="aws:kms")   
                in_bucket = True
                break
            if not in_bucket:
                create_bucket(bucket_name)
                s3.put_object(Bucket=bucket_name, Key=file_name, Body=multipart_content["file"],
                              ServerSideEncryption="aws:kms")    
    
    
            # on upload success
        return {
                "statusCode": 200,
                "body": json.dumps("File uploaded successfully!")
            }
    else:
            # on upload failure
        return {
                "statusCode": 500,
                "body": json.dumps("Upload failed!")
            }
    
   

但这仅适用于最大 10 MB 的文件。我想上传所有文件扩展名,还有小文件和大于 10 MB 的文件?

如何修改这段代码?预设网址?分段上传?

我不确定如何实现这一点?

谢谢!

标签: python-3.xamazon-web-servicesamazon-s3aws-lambdaboto3

解决方案


文件大于 10 MB?

遗憾的是,您无法通过 API 网关执行此操作。它的硬限制10 MB。常见的解决方法是使用S3 预签名 url将文件上传到 S3。这需要更改您的架构,因为要上传到 S3,您不能使用 API 网关。


推荐阅读