400 (Неверный запрос) при попытке загрузить изображения в AWS S3 из браузера

#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 скриншот ошибки 2скриншот ошибки 2

Ответ №1:

Я думаю, что проблема заключается в имени поля POST «img» для файлового объекта. Эта ссылка использует file в качестве ключевого имени файла. https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html вы можете попробовать использовать «file» вместо «img».

Комментарии:

1. Только что попробовал, все равно не работает. Он по-прежнему выдает ту же ошибку.