S3 Python-使用预先指定的部分URL将多部分上载到S3
我尝试使用预签名的部分URL进行多部分上载失败 这是我遵循的过程(1-3在服务器端,4在客户端):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
导入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”]
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,如果您喜欢这个答案并且它对您有效,请批准它并向上投票,以及通过堆栈溢出推荐。谢谢。