Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
S3 Python-使用预先指定的部分URL将多部分上载到S3_Python_Amazon Web Services_Amazon S3_Boto3 - Fatal编程技术网

S3 Python-使用预先指定的部分URL将多部分上载到S3

S3 Python-使用预先指定的部分URL将多部分上载到S3,python,amazon-web-services,amazon-s3,boto3,Python,Amazon Web Services,Amazon S3,Boto3,我尝试使用预签名的部分URL进行多部分上载失败 这是我遵循的过程(1-3在服务器端,4在客户端): 实例化boto客户端 导入boto3 从botocore.client导入配置 s3=boto3.client( “s3”, region\u name=aws.default\u region, aws\u访问密钥\u id=aws.access\u密钥\u id, aws\u secret\u access\u key=aws.secret\u access\u key, config=con

我尝试使用预签名的部分URL进行多部分上载失败

这是我遵循的过程(1-3在服务器端,4在客户端):

  • 实例化boto客户端
  • 导入boto3
    从botocore.client导入配置
    s3=boto3.client(
    “s3”,
    region\u name=aws.default\u region,
    aws\u访问密钥\u id=aws.access\u密钥\u id,
    aws\u secret\u access\u key=aws.secret\u access\u key,
    config=config(signature\u version=“s3v4”)
    )
    
  • 启动多部分上传
  • upload=s3.create\u multipart\u upload(
    铲斗=AWS_S3_铲斗,
    键=键,
    Expires=datetime.now()+timedelta(天=2),
    )
    upload\u id=upload[“UploadId”]
    
  • 为部件上载创建预签名的URL
  • 
    part=从客户提交的数据生成part对象(…)
    part.presigned_url=s3.generate_presigned_url(
    ClientMethod=“上传零件”,
    Params={
    “桶”:AWS_S3_桶,
    “密钥”:上传密钥,
    “UploadId”:上传id,
    “零件号”:零件号,
    “ContentLength”:零件尺寸,
    “ContentMD5”:part.md5,
    },
    ExpiresIn=3600,#1h
    HttpMethod=“PUT”,
    )
    
    将预签名的URL返回到客户端

  • 在客户端上,尝试使用
    请求上载部件
  • part=receive\u part\u object\u from\u server(…)
    将io.open(文件名“rb”)作为f:
    f、 搜索(部分偏移)
    缓冲区=io.BytesIO(f.read(部件大小))
    r=requests.put(
    部分。预签名的url,
    数据=缓冲区,
    标题={
    “内容长度”:str(零件尺寸),
    “Content-MD5”:part.MD5,
    “主机”:“AWS_S3_BUCKET.S3.amazonaws.com”,
    },
    )
    
    当我尝试上传时,我会得到:

    urllib3.exceptions.ProtocolError:
    (“连接中止”,断开管道错误(32,“断开管道”))
    
    或:

    
    NoSuchUpload
    指定的上载不存在。上载ID可能无效,
    或者上载可能已中止或完成。
    正确的上传ID
    ...
    ...
    
    即使上传仍然存在,我可以列出它

    谁能告诉我我做错了什么吗?

    你试过了吗?以下是关于它的AWS Python参考:

    这可能会从客户端角度解决代理限制问题(如果有):

    最后,您可以尝试使用旧的RESTAPI,尽管我认为问题不在您的代码中,也不在boto3中:

    是一个命令实用程序,它可以做完全相同的事情,您可能希望在尝试时给出它,看看它是否有效。如果是这样,就很容易找到你的代码和他们的代码之间的差异。如果没有,我会仔细检查整个过程。下面是一个如何使用
    aws
    commandline上传文件的示例

    事实上,如果它真的起作用。也就是说,你可以使用aws s3命令来回复上传,然后我们需要重点关注分散url的使用。您可以在此处检查url的外观:

    这是JSSDK,但是那里的人谈论原始URL和参数,所以你应该能够发现你的URL和工作的URL之间的差异

    另一个选择是试试这个脚本,它使用js从web浏览器上传文件,使用分散的URL

    如果工作正常,您可以检查通信并观察用于上载每个部分的确切URL,您可以将其与系统生成的URL进行比较


    顺便说一句。一旦你有了一个用于多部分上传的工作url,你就可以使用aws s3预签名url来获得发布的url,这应该让你只需使用
    curl
    就可以完成上传,从而完全控制上传过程。

    预签名url方法

    您可以通过以下链接学习AWS S3为Python SDK(Boto3)预先指定的URL以及如何使用多部分上载API:

  • 调动经理方法

    Boto3提供了使用S3管理各种类型传输的接口,以自动管理多部分和非多部分上传。为确保多部分上载仅在绝对必要时发生,您可以使用
    multipart\u threshold
    配置参数

    请尝试使用以下代码作为Transfer Manager方法:

    import boto3
    from boto3.s3.transfer import TransferConfig
    import botocore
    from botocore.client import Config
    from retrying import retry
    import sysdef upload(source, dest, bucket_name):
        try:
            conn = boto3.client(service_name="s3", 
                                aws_access_key_id=[key],    
                                aws_secret_access_key=[key],                   
                                endpoint_url=[endpoint],
                                config=Config(signature_version='s3')
            config = TransferConfig(multipart_threshold=1024*20,  
                            max_concurrency=3, 
                            multipart_chunksize=1024*20, 
                            use_threads=True)
            conn.upload_file(Filename=source, Bucket=bucket_name,     
                             Key=dest, Config=config)
        except Exception as e:
            raise Exception(str(e))def download(src, dest, bucket_name):
        try:
            conn = boto3.client(service_name="s3", 
                                aws_access_key_id=[key],    
                                aws_secret_access_key=[key],                   
                                endpoint_url=[endpoint],
                                config=Config(signature_version='s3')
            config = TransferConfig(multipart_threshold=1024*20,  
                            max_concurrency=3, 
                            multipart_chunksize=1024*20, 
                            use_threads=True)
            conn.download_file(bucket=bucket_name, key=src, 
                              filename=dest, Config=config)                
        except AWSConnectionError as e:
            raise AWSConnectionError("Unable to connect to AWS")
        except Exception as e:
            raise Exception(str(e))if __name__ == '__main__': 
    upload(source, dest, bucket_name)
    download(src, dest, bucket_name)
    
    import json
    from uuid import uuid4
    
    import boto3
    
    
    def get_upload_credentials_for(bucket, key, username):
        arn = 'arn:aws:s3:::%s/%s' % (bucket, key)
        policy = {"Version": "2012-10-17",
                  "Statement": [{
                      "Sid": "Stmt1",
                      "Effect": "Allow",
                      "Action": ["s3:PutObject"],
                      "Resource": [arn],
                  }]}
        client = boto3.client('sts')
        response = client.get_federation_token(
            Name=username, Policy=json.dumps(policy))
        return response['Credentials']
    
    
    def client_from_credentials(service, credentials):
        return boto3.client(
            service,
            aws_access_key_id=credentials['AccessKeyId'],
            aws_secret_access_key=credentials['SecretAccessKey'],
            aws_session_token=credentials['SessionToken'],
        )
    
    
    def example():
        bucket = 'mybucket'
        filename = '/path/to/file'
    
        key = uuid4().hex
        print(key)
    
        prefix = 'tmp_upload_'
        username = prefix + key[:32 - len(prefix)]
        print(username)
        assert len(username) <= 32  # required by the AWS API
    
        credentials = get_upload_credentials_for(bucket, key, username)
        client = client_from_credentials('s3', credentials)
        client.upload_file(filename, bucket, key)
        client.upload_file(filename, bucket, key + 'bob')  # fails
    
    
    example()
    
    from minio import Minio
    from minio.error import ResponseError
    
    s3client = Minio('s3.amazonaws.com',
                        access_key='YOUR-ACCESSKEYID',
                        secret_key='YOUR-SECRETACCESSKEY')
    
    # Put an object 'my-objectname' with contents from 'my-filepath'
    
    try:    
        s3client.fput_object('my-bucketname', 'my-objectname', 'my-filepath')
    except ResponseError as err:
        print(err)
    
    AWS STS方法

    您还可以按照AWS安全令牌服务(STS)方法生成一组临时凭据来完成任务

    针对AWS STS方法,尝试以下代码:

    import boto3
    from boto3.s3.transfer import TransferConfig
    import botocore
    from botocore.client import Config
    from retrying import retry
    import sysdef upload(source, dest, bucket_name):
        try:
            conn = boto3.client(service_name="s3", 
                                aws_access_key_id=[key],    
                                aws_secret_access_key=[key],                   
                                endpoint_url=[endpoint],
                                config=Config(signature_version='s3')
            config = TransferConfig(multipart_threshold=1024*20,  
                            max_concurrency=3, 
                            multipart_chunksize=1024*20, 
                            use_threads=True)
            conn.upload_file(Filename=source, Bucket=bucket_name,     
                             Key=dest, Config=config)
        except Exception as e:
            raise Exception(str(e))def download(src, dest, bucket_name):
        try:
            conn = boto3.client(service_name="s3", 
                                aws_access_key_id=[key],    
                                aws_secret_access_key=[key],                   
                                endpoint_url=[endpoint],
                                config=Config(signature_version='s3')
            config = TransferConfig(multipart_threshold=1024*20,  
                            max_concurrency=3, 
                            multipart_chunksize=1024*20, 
                            use_threads=True)
            conn.download_file(bucket=bucket_name, key=src, 
                              filename=dest, Config=config)                
        except AWSConnectionError as e:
            raise AWSConnectionError("Unable to connect to AWS")
        except Exception as e:
            raise Exception(str(e))if __name__ == '__main__': 
    upload(source, dest, bucket_name)
    download(src, dest, bucket_name)
    
    import json
    from uuid import uuid4
    
    import boto3
    
    
    def get_upload_credentials_for(bucket, key, username):
        arn = 'arn:aws:s3:::%s/%s' % (bucket, key)
        policy = {"Version": "2012-10-17",
                  "Statement": [{
                      "Sid": "Stmt1",
                      "Effect": "Allow",
                      "Action": ["s3:PutObject"],
                      "Resource": [arn],
                  }]}
        client = boto3.client('sts')
        response = client.get_federation_token(
            Name=username, Policy=json.dumps(policy))
        return response['Credentials']
    
    
    def client_from_credentials(service, credentials):
        return boto3.client(
            service,
            aws_access_key_id=credentials['AccessKeyId'],
            aws_secret_access_key=credentials['SecretAccessKey'],
            aws_session_token=credentials['SessionToken'],
        )
    
    
    def example():
        bucket = 'mybucket'
        filename = '/path/to/file'
    
        key = uuid4().hex
        print(key)
    
        prefix = 'tmp_upload_'
        username = prefix + key[:32 - len(prefix)]
        print(username)
        assert len(username) <= 32  # required by the AWS API
    
        credentials = get_upload_credentials_for(bucket, key, username)
        client = client_from_credentials('s3', credentials)
        client.upload_file(filename, bucket, key)
        client.upload_file(filename, bucket, key + 'bob')  # fails
    
    
    example()
    
    from minio import Minio
    from minio.error import ResponseError
    
    s3client = Minio('s3.amazonaws.com',
                        access_key='YOUR-ACCESSKEYID',
                        secret_key='YOUR-SECRETACCESSKEY')
    
    # Put an object 'my-objectname' with contents from 'my-filepath'
    
    try:    
        s3client.fput_object('my-bucketname', 'my-objectname', 'my-filepath')
    except ResponseError as err:
        print(err)
    

    嗨,法比奥,谢谢你的回答。我没有代理上传,所以我没有在命令行客户端和AWS之间使用Django或其他任何东西。我还发现了那个博客页面,并根据它做了所有事情,但我无法让它工作。此外,一个部件的上载失败,因此我甚至没有找到完成上载的代码。编辑以重试:)此部件不是多部件上载:(另一次尝试!:DHi Piotr。我不是在下载,我是在进行多部分上传。当我测试代码时,所有的工作都在同一台机器上完成,所以它不是IP的更改。对的,thx。我已经了解了一些,并更新了答案。\n您的代码与一个小的断开部分类隔离工作。您如何处理Completee多部分上传请求?你确定在客户端可以上传之前它没有被触发吗?你确定你发送给客户端的URL没有以某种方式被转换吗?你非常接近拥有一个简单的测试平台,我会把它变成一个简单的端到端测试平台,只用于多部分上传以验证代码,尽管我怀疑我遇到的问题未显示代码中的。我还尝试使用预签名URL执行多部分上载。您能建议如何解决此问题吗?@Viktor Kerkez,如果您喜欢这个答案并且它对您有效,请批准它并向上投票,以及通过堆栈溢出推荐。谢谢。