#python-3.x #django #amazon-s3 #file-upload
#python-3.x #django #amazon-s3 #загрузка файла
Вопрос:
Я боролся с этим уже несколько недель. Я пытаюсь загрузить изображения в AWS S3 непосредственно из браузера, используя функцию generate_presigned_post() boto3. Похоже, что код на стороне сервера работает хорошо, я получаю подписанный URL-адрес, но когда я пытаюсь загрузить с помощью javascript, я получаю ошибку 400 bad request.
Серверный код:
@csrf_protect
def file_upload_view(request):
if request.method == 'POST':
file_names = request.POST.getlist('img_names') #extracts a list of all file names for files selected by the user.
dataList = []
session = boto3.Session()
#create an s3 object for uploads.
s3 = session.client(
's3',
region_name=settings.AWS_S3_REGION_NAME,
aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
config = Config(signature_version = 's3v4')
)
print(settings.AWS_ACCESS_KEY_ID)
S3BUCKET = settings.AWS_STORAGE_BUCKET_NAME
for fileName in file_names:
fname = randomString(30)
fname = "media/Ad_images/{}.webp".format(fname)
presigned_post = s3.generate_presigned_post(
Bucket=S3BUCKET,
Key= fileName,
Fields={"acl": "public-read", "Content-Type": 'image/jpg'},
Conditions=[
{"acl": "public-read"},
{"Content-Type": 'image/jpg'},
["content-length-range", 2, 5]
],
ExpiresIn=3600
)
dataList.append(
{
'original_fname': fileName,
'data': presigned_post,
'url': 'https://{}.s3.eu-west-2.amazonaws.com/{}'.format(settings.AWS_STORAGE_BUCKET_NAME, fname)
}
)
return JsonResponse(dataList, safe=False)
Код Javascript (на стороне клиента):
async function upload(input) {
var form = document.querySelector("form#imgsForm");
var form_data = new FormData(form);
var fdata = new FormData();
images = $("#adImgs")[0].files;
emptyDisplayDivs = $('*[data-loaded="false"]');
if (images.length > 10 || images.length > emptyDisplayDivs.length) {
alert(
"Only 10 pictures are allowed. You have selected more than 10 pictures."
);
return;
}
inprogress(images.length);
for(var i = 0; i < images.length; i ){
fdata.append('img_names', images[i].name);
console.log(images[i].type);
}
const csrftoken = $("[name=csrfmiddlewaretoken]").val();
fdata.append('csrfmiddlewaretoken', csrftoken);
var xhr = new XMLHttpRequest();
xhr.open("POST", "/ads/upload_imgs/");
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status === 200){
var response = JSON.parse(xhr.responseText);
// console.log(response);
upload_images(response, images);
}
else{
alert("Could not get signed URL.");
}
}
};
xhr.send(fdata);
}
function upload_images(resp, imgs) {
for (var j = 0; j < resp.length; j ) {
var xhr = new XMLHttpRequest();
xhr.open("POST", resp[j].data.url);
var postData = new FormData();
for (key in resp[j].data.fields) {
console.log(resp[j].data.fields[key]);
postData.append(key, resp[j].data.fields[key]);
}
for (var i = 0; i < imgs.length; i ) {
if (resp[j].original_fname == imgs[i].name)
postData.append("img", imgs[i]);
}
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200 || xhr.status === 204) {
showImg(resp[j].url);
} else {
alert("Could not upload file.");
}
}
};
xhr.send(postData);
}
}
Код ошибки:
<Error>
<Code>
MaxPostPreDataLengthExceeded
</Code>
<Message>
Your POST request fields preceeding the upload file was too large.
</Message>
<MaxPostPreDataLengthBytes>
20480
</MaxPostPreDataLengthBytes>
<RequestId>
F33A2AAAE78BDCC3
</RequestId>
<HostId>
F7DYCoGiITtv52G4 mpTyFgR8Dft7/OrfxcHlBRLoG3wFZevYUMhvq136vDJVcxG6SKp5KJA/uU=
</HostId>
</Error>
Ответ №1:
Я думаю, что проблема заключается в имени поля POST «img» для файлового объекта. Эта ссылка использует file в качестве ключевого имени файла. https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html вы можете попробовать использовать «file» вместо «img».
Комментарии:
1. Только что попробовал, все равно не работает. Он по-прежнему выдает ту же ошибку.