Lambda Python 3.X中指定区域的Boto3 AWS S3 generate_presigned_url中存在错误?

tf7tbtn2  于 2023-02-21  发布在  Python
关注(0)|答案(1)|浏览(131)

我试着写一个python lambda函数,返回一个预先签名的url来放置一个对象。

import os
import boto3
import json

import boto3

session = boto3.Session(region_name=os.environ['AWS_REGION'])
s3 = session.client('s3', region_name=os.environ['AWS_REGION'])

upload_bucket = 'BUCKER_NAME'  # Replace this value with your bucket name!
URL_EXPIRATION_SECONDS = 30000    # Specify how long the pre-signed URL will be valid for

# Main Lambda entry point
def lambda_handler(event, context):
    return get_upload_url(event)

def get_upload_url(event):
    key = 'testimage.jpg' # Random filename we will use when uploading files

    # Get signed URL from S3
    s3_params = {
        'Bucket': upload_bucket,
        'Key': key,
        'Expires': URL_EXPIRATION_SECONDS,
        'ContentType': 'image/jpeg' # Change this to the media type of the files you want to upload
    }

    # Get signed URL
    upload_url = s3.generate_presigned_url(
        'put_object',
        Params=s3_params,
        ExpiresIn=URL_EXPIRATION_SECONDS
    )
    
    return {
        'statusCode': 200,
        'isBase64Encoded': False,
        'headers': {
            'Access-Control-Allow-Origin': '*'
        },
        'body': json.dumps(upload_url)
    }

代码本身可以工作,并返回一个带签名的URL,格式为“https://BUCKET_NAME.s3.amazonaws.com/testimage. jpg?...”
但是,当使用POSTMAN尝试放置对象时,它加载而不结束。
最初我认为这是因为我的代码,过了一段时间我写了一个NodeJS函数做同样的事情:

const AWS = require('aws-sdk')
AWS.config.update({ region: process.env.AWS_REGION })
const s3 = new AWS.S3()
const uploadBucket = 'BUCKET_NAME'  // Replace this value with your bucket name!   
const URL_EXPIRATION_SECONDS = 30000    // Specify how long the pre-signed URL will be valid for

// Main Lambda entry point
exports.handler = async (event) => {
  return await getUploadURL(event)
}

const getUploadURL = async function(event) {
  const randomID = parseInt(Math.random() * 10000000)
  const Key = 'testimage.jpg' // Random filename we will use when uploading files

  // Get signed URL from S3
  const s3Params = {
    Bucket: uploadBucket,
    Key,
    Expires: URL_EXPIRATION_SECONDS,
    ContentType: 'image/jpeg' // Change this to the media type of the files you want to upload
  }
  
  return new Promise((resolve, reject) => {
    // Get signed URL
    let uploadURL = s3.getSignedUrl('putObject', s3Params)
    resolve({
      "statusCode": 200,
      "isBase64Encoded": false,
      "headers": {
        "Access-Control-Allow-Origin": "*"
      },
      "body": JSON.stringify(uploadURL)
    })
  })
}

NodeJs版本给了我一个格式为“https://BUCKET_www.example.com“的URLNAME.s3.eu-west-1.amazonaws.com/testimage.jpg?
两者的主要区别是aws子域,当使用NodeJS时,它给出“BUCKET_NAME.s3.eu-west-1.amazonaws.com”,当使用Python时,给出“https://BUCKET_NAME.s3. amazonaws.com
当使用python时,该区域不出现。我试过,使用python生成的签名url手动添加“s3.eu-west-1”,它工作!!
这是AWS Boto 3 python库中的bug吗?正如您所看到的,在python代码中,我尝试指定区域,但它没有执行任何操作。
有什么想法吗,伙计们?我想解开这个谜团:)
先谢谢你了,
莱奥

nkhmeac6

nkhmeac61#

我能够在us-east-1中重现这个问题。Github中有一些bug(例如,thisthis),但建议的解决方案不一致。
解决方法是为bucket创建一个面向Internet的接入点,然后将接入点的完整ARN赋给upload_bucket变量。
请注意,Lambda将创建一个预签名的URL,但只有在Lambda具有附加到其执行角色的适当权限策略时,它才能工作。

相关问题