【问题标题】:Upload file to s3 from vuejs and Django backend从 vuejs 和 Django 后端将文件上传到 s3
【发布时间】:2019-04-27 03:46:02
【问题描述】:

我想在 Django 中生成一个签名 URL,使用 Axios Ajax 将其发送到前端,然后使用该 URL 将文件直接从 Vue JS 上传到 S3。在以下代码中,当用户单击上传按钮时 - 调用 Vue 方法 uploadButtonClicked,该方法调用 Django 函数 ajaxSendPresignedUrlForS3,该函数生成预签名的帖子 URL。这个url传回vueuploadButtonClicked,然后调用vue方法uploadFile

到目前为止,网址生成成功。但是在将文件发布到 S3 存储桶时,我收到错误 Error: Request failed with status code 403。我一直在阅读并对代码进行一些修改,这会导致新的错误,如 412、405 等。

Django 代码

def ajaxSendPresignedUrlForS3(request):
    input=json.loads(request.body.decode('utf-8')); print('ajaxSendPresignedUrlForS3');
    S3_BUCKET = os.environ.get('S3_BUCKET')
    file_name = input['file_name'][0]
    file_type = input['file_type'][0]
    s3 = boto3.client('s3',
            aws_access_key_id=os.environ.get('AWS_ACCESS_KEY_ID'),
            aws_secret_access_key=os.environ.get('AWS_SECRET_ACCESS_KEY'),
            region_name='us-east-2',
            config=Config(signature_version='s3v4'),
            )
    presigned_post = s3.generate_presigned_post(
            Bucket = S3_BUCKET,
            Key = file_name,
            Fields = {"Content-Type": 'multipart/form-data'},
            Conditions = [{"Content-Type": 'multipart/form-data'}],

            ExpiresIn = 300 #seconds
    )
    return JsonResponse({'data': presigned_post})

Javascript Vue 代码

Vue 方法一:

uploadButtonClicked:function(){ //gettting presigned POST URL from django
          console.log('uploadButtonClicked');
          //call axios ajax to get presigned URL from django and then upload file to s3 using axios func "upLoadFile"
          axios({
                method: 'post',
                baseURL: window.location.origin, //we need base url coz this ajax can be called from any page on timeout
                url: 'main/ajaxSendPresignedUrlForS3/',
                data: {
                      file_name: this.inputFilesName,
                      file_type: this.inputFilesType,
                    },
                responseType: 'json', //server will response with this datatype
              })
              .then ( function (response){
                  data=response.data;
                  console.log('uploadButtonClicked succes. data =',data ); //works
                  this.upLoadFile(data); //upload file to S3

              }.bind(this))
              .catch ( function (error){
                console.log('uploadButtonClicked error=',error);
              });

      },

Vue方法二:

upLoadFile:function(data){ //upload file directly to s3
          console.log('upLoadFile')
          var postData = new FormData(); //its type to JS inbuilt form
          console.log('data.data.fields=',data.data.fields,'\nKeys =')
          for(key in data.data.fields){
              console.log(key);
              postData.append(key, data.data.fields[key]);
          }
          postData.append('file', document.getElementById('id_inputButtonReal').files[0]);
          console.log('postData=',postData)
          axios({
                method: 'get',
                url: data.data.url+new Date().getTime(),
                data: {
                      postData: postData,
                    },
                // responseType: 'json', //server will response with this datatype
              })
              .then ( function (response){
                  data=response.data;
                  console.log('upLoadFile success');

              }.bind(this))
              .catch ( function (error){
                console.log('upLoadFile error=',error);
              });
      },

我可以直接从 Django 将文件上传到 s3。这可能意味着我的 python 部分是正确的:

    from boto3.s3.transfer import S3Transfer
    myfile='/home/user/img1.jpg';
    transfer = S3Transfer(s3); #s3 is declared in above code
    transfer.upload_file(myfile, S3_BUCKET,'snake2.jpg') ; print('upload successful');

谢谢

【问题讨论】:

  • 你有没有尝试过?
  • 是的,我用迄今为止尝试过的代码更新了我的问题

标签: django vue.js amazon-s3


【解决方案1】:

错误解释:我以字典的形式向 S3 发送数据。 S3 喜欢直接 postData。

上面的 Django 代码完全没问题。为了便于理解,我已将 Javascript 代码合并为一个较小的版本。

  uploadButtonClickedforStackoverflow:function(){ //gettting presigned POST URL from django and then uploading file to S3 using that url
      axios({
            method: 'post',
            baseURL: window.location.origin, //we need base url coz this ajax can be called from any page on timeout
            url: 'main/ajaxSendPresignedUrlForS3/',
            data: { file_name: 'snake.jpg' },//sending filename to django so it can build a presigned POST URL granting frontend permission to upload
            responseType: 'json', //server will response with this datatype
          })
          .then ( function (response){
              presigned_post=response.data
              var postData = new FormData(); //its type to JS inbuilt form
              for(key in presigned_post.fields){ //appending all keys sent by django to our JS FormData object
                    postData.append(key, presigned_post.fields[key]);
              }
              var file=document.getElementById('id_inputButtonReal').files[0]; //id_inputButtonReal is id of HTML input element
              postData.append('file', file);
              axios({
                    method: 'post',
                    url: presigned_post.url,
                    data: postData, //dont sent data as {data:postData}, instead S3 likes it just by itself
                    })
          });

  },

【讨论】:

  • 好帖子!由于 AWS 预先签名的响应中的“403 响应”不明确,我找到了您的答案,发现我的代码相似。通过授予后端代码“s3:PutObject”权限解决了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-02
  • 2016-02-21
  • 2018-12-15
  • 2017-08-18
  • 2016-11-22
  • 1970-01-01
  • 2018-12-28
相关资源
最近更新 更多