使用 preSignedUrl 上传/发布任意目录/文件到 S3

问题描述 投票:0回答:1

我正在尝试找出一种方法将文件发送到 S3 到具有任意“目录”和“文件名”的签名 URL。了解 S3 没有目录。

我可以使用以下命令成功生成签名网址并上传任意文件名:

Lambda 创建签名 URL:

def lambda_handler(event, context):
    
    
    def create_presigned_post(bucket_name, object_name="${filename}",
                              fields=None, conditions=None, expiration=3600):
        """Generate a presigned URL S3 POST request to upload a file
    
        :param bucket_name: string
        :param object_name: string
        :param fields: Dictionary of prefilled form fields
        :param conditions: List of conditions to include in the policy
        :param expiration: Time in seconds for the presigned URL to remain valid
        :return: Dictionary with the following keys:
            url: URL to post to
            fields: Dictionary of form fields and values to submit with the POST
        :return: None if error.
        """
    
        # Generate a presigned S3 POST URL
        s3_client = boto3.client('s3')
        try:
            response = s3_client.generate_presigned_post(bucket_name,
                                                         object_name,
                                                         Fields=fields,
                                                         Conditions=conditions,
                                                         ExpiresIn=expiration)
        except ClientError as e:
            logging.error(e)
            return None
    
        # The response contains the presigned URL and required fields
        return response
    
    bucketName = "myBucket"
    
    s3client = boto3.client("s3")
    signed_url = create_presigned_post(bucketName)
    
    return signed_url

请求上传文件:

session = boto3.Session(profile_name='dev')
object_name = 'test2.txt'
bucket = 'myBucket'

response = {
  "url": "https://mys3url.com",
  "fields": {
    "key": "${filename}",
    "AWSAccessKeyId": "...",
    "x-amz-security-token": "...",
    "policy": "...",
    "signature": "..."
  }
}


if response is None:
    exit(1)

# Demonstrate how another Python program can use the pre-signed URL to upload a file
with open(object_name, 'rb') as f:
    s3_object_name = f"this/is/a/test/dir/{object_name}"
    files = {'file': (s3_object_name, f)}
    http_response = requests.post(response['url'], data=response['fields'], files=files)
# If successful, returns HTTP status code 204
print(f'File upload HTTP status code: {http_response.status_code}')
print(f'{http_response.content}')

当文件 test2.txt 写入存储桶“root”时,这基本上可以正常工作。

但是我想将其上传到

this/is/a/test/dir/
或S3存储桶中的任何其他目录。

我确实理解预签名 url 本质上是限制性的,并且这种限制可能是设计使然,但是如果 s3 没有目录结构,只需命名文件即可将其写入“目录”?

使用

${filename}
允许我将任何文件名写入 S3,但似乎会从文件名中删除任何目录结构。

有用的链接帮助我走到这一步。

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3/client/generate_presigned_post.html

https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-presigned-urls.html

amazon-s3 post python-requests put pre-signed-url
1个回答
0
投票

但是我想将其上传到

this/is/a/test/dir/
或S3存储桶中的任何其他目录。

来自文档:

Key (string)
– 键名,可以选择在末尾添加
${filename}
以附加提交的文件名。请注意,关键相关条件和字段已为您填写,不应包含在“字段”或“条件”参数中。

像这样使用它:

s3_client.generate_presigned_post(bucket_name, "this/is/a/test/dir/{$filename}")

这将生成一个带有签名 POST 策略的 URL,该策略将接受多部分表单数据并从其文件部分的

$filename
填充
Content-Disposition: filename
部分。

© www.soinside.com 2019 - 2024. All rights reserved.