我生成了一个预签名URL,用于通过Python支持的API将文件上传到AWS S3。用户在浏览器中选择文件后,此部分将接收文件名信息(请参见下文),并返回带有基本URL和字段的JSON有效负载(请参见下文)。
import logging
import boto3
from botocore.exceptions import ClientError
def create_presigned_post(bucket_name, object_name,
fields=None, conditions=None, expiration=3600):
# 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
这是我从此函数获得的JSON响应。 (我更改/缩写了一些值,但您明白了。)
{
"url": "https://s3.us-east-2.amazonaws.com/my_bucket_name",
"fields": {
"key": "some.txt",
"AWSAccessKeyId": "ASI...",
"x-amz-security-token": "Ag9o...",
"policy": "eyJ...=",
"signature": "jn...="
}
}
这是我用来上传文件的HTML表单。我有一些原始的Javascript可以跟踪对表单的更改,并在更改后(例如,文件选择)更新表单的URL_VALUE
和每个表单项的VALUE
。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<!-- Copy the 'url' value returned by S3Client.generate_presigned_post() -->
<form action="URL_VALUE" method="post" enctype="multipart/form-data">
<!-- Copy the 'fields' key:values returned by S3Client.generate_presigned_post() -->
<input type="hidden" name="key" value="VALUE" />
<input type="hidden" name="AWSAccessKeyId" value="VALUE" />
<input type="hidden" name="policy" value="VALUE" />
<input type="hidden" name="signature" value="VALUE" />
File:
<input type="file" name="file" /> <br />
<input type="submit" name="submit" value="Upload to Amazon S3" />
</form>
</body>
</html>
这种HTML表单本身可以正常工作,但是我尝试添加一些Javascript(包括香草和JQuery),因此我可以跟踪文件进度并禁用表单输入,直到上传完成。
我无法使用Javascript!
我尝试了很多示例(同样是香草JS和JQuery)。
最近有没有人实施过这个并且可以提供帮助?
答案 0 :(得分:1)
我相信您必须传递
之类的AWS机密"key": "some.txt",
"AWSAccessKeyId": "ASI...",
"x-amz-security-token": "Ag9o...",
"policy": "eyJ...=",
"signature": "jn...="
作为标题。
您是否正在使用fetch
库?
能否将JS代码发布到?
答案 1 :(得分:0)
好的,找到了一个ridiculously simple香草JS示例,可以正常工作!
$(document).ready(function () {
var PRESIGNED_URL = ""
$('input[type="file"]').change(function (e) {
var fileName = e.target.files[0].name;
var settings = {
"async": true,
"crossDomain": true,
"url": "https://my_api.com",
"method": "POST",
"headers": {
"Content-Type": "application/x-www-form-urlencoded",
},
"data": {
"filename": fileName
}
}
$.ajax(settings).done(function (response) {
$("#filename").html(fileName)
PRESIGNED_URL = response["url"]
$("#form").attr("action", response["url"])
$("#key").val(response["fields"]["key"])
$("#AWSAccessKeyId").val(response["fields"]["AWSAccessKeyId"])
$("#policy").val(response["fields"]["policy"])
$("#signature").val(response["fields"]["signature"])
$("#x-amz-security-token").val(response["fields"]["x-amz-security-token"])
return
});
});
$("#button").on("click", function (e) {
var form = document.getElementById('form');
var formData = new FormData(form);
var xhr = new XMLHttpRequest();
// Add any event handlers here...
xhr.upload.addEventListener('progress', function(e) {
var percent_complete = (e.loaded / e.total)*100;
// Percentage of upload completed
console.log(percent_complete);
});
xhr.onloadstart = function (e) {
console.log("start")
}
xhr.onloadend = function (e) {
console.log("end")
}
xhr.open('POST', PRESIGNED_URL, true);
xhr.send(formData);
$("#filename").html("")
})
});
有很多相似的变体,但是效果很好。
(我相信对许多人来说似乎很明显,但我只是根据需要进行前端开发...)
答案 2 :(得分:0)
比您发布的内容还要简单。
fetch(yourSignedUrl, {
method: 'PUT',
body: file,
headers: {
'Content-Type': file.type
}
}).then((res) => {
if (!res.ok) {
throw new Error(res.statusText);
}
return res.headers.get('ETag');
});