I would like to generate a signed URL in Django, send it to frontend using Axios Ajax and then using that url upload a file directly from Vue JS to S3. In following code when user clicks on upload button - Vue method uploadButtonClicked is called which calls Django function ajaxSendPresignedUrlForS3 which generates presigned post url. This url is passed back to vue uploadButtonClicked and then vue method uploadFile is called.
So far url generation is sucessful. But on posting file to S3 bucket I get error Error: Request failed with status code 403. I have been reading around and making some modifications with the code which results in new errors like 412, 405 etc.
Django code
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 code
Vue method 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 method 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);
});
},
I was able to upload file to s3 directly from Django though. Which probably means my python part is correct:
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');
Thanks