我想在Django中生成一个签名的URL,使用Axios Ajax将其发送到前端,然后使用该URL将文件直接从Vue JS上传到S3。在下面的代码中,当用户单击上传按钮时-调用Vue方法uploadButtonClicked
,该方法调用Django函数ajaxSendPresignedUrlForS3
,该函数生成带预签名的帖子网址。该URL传递回vue uploadButtonClicked
,然后调用vue方法uploadFile
。
到目前为止,URL生成成功。但是在将文件发布到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方法1:
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方法2:
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');
谢谢
答案 0 :(得分:0)
错误说明:我正在以字典字典的形式向S3发送数据。 S3喜欢直接发布数据。
以上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
})
});
},