Upload to S3 - The body of your POST request is not well-formed multipart/form-data - amazon-s3

I am trying to upload a file to s3 using this guide: https://www.dtreelabs.com/blog/s3-direct-file-upload-using-presigned-url-from-react-and-rails which long story short describes how to use a presigned url to upload files to S3.
Whenever I send the request to my s3 bucket to upload a given file, I am getting an error The body of your POST request is not well-formed multipart/form-data.
My front end code is:
const handleImageUpload = (file) => {
ApiUtils.getPresignedS3Url({ fileName: file.name }).then((uploadParams) => {
if (uploadParams) {
uploadToS3(uploadParams, file)
}
})
const uploadToS3 = (uploadParams, file) => {
const { url, s3_upload_params: fields } = uploadParams
const formData = new FormData()
formData.append("Content-Type", file.type)
Object.entries(fields).forEach(([k, v]) => {
formData.append(k, v)
})
formData.append("file", file)
fetch(url, {
method: "POST",
headers: {
"Content-Type": "multipart/form-data",
},
undefined,
body: formData,
})
.then((awsResponse) => {
if (awsResponse.ok) {
console.log("success")
} else {
console.log(awsResponse)
}
})
.catch((error) => {
console.log("blew up")
console.log(error)
})
}
Several other stack overflow answers involve using Axios or new XMLHttpRequest. These have resulted in the same error for me.
the end of the payload I am sending to amazon is:
------WebKitFormBoundary7cFRTGgKGqbDhagf
Content-Disposition: form-data; name="file"; filename="uploadMe.html"
Content-Type: text/html
------WebKitFormBoundary7cFRTGgKGqbDhagf--
I believe the issue may be something along the lines of the body of my file isn't being included in the request. I'm investigating this now.
Any help would be appreciated, thank you <3

https://github.com/github/fetch/issues/505#issuecomment-293064470 describes why this is an issue. Posting the text incase the comment ever gets removed:
Setting the Content-Type header manually means it's missing the boundary parameter. Remove that header and allow fetch to generate the full content type. It will look something like this:
Content-Type: multipart/form-data;boundary=----WebKitFormBoundaryyrV7KO0BoCBuDbTL
Fetch knows which content type header to create based on the FormData object passed in as the request body content.
removing "Content-Type": "multipart/form-data" above indeed seems to result in the mujltipart form data being formatted correctly.

Related

React native post image to server Required request part 'file' is not present

There is no problem with sending photos from Postman.
header is ---> 'Content-Type':'application/x-www-form-urlencoded'
body is ----> form-data , {file : image..}
Sending headers to x-www-form-urlencoded or multi-part/form-data does not work.
(HTTP Status 400 – Bad Request)
Note that there is no image capacity limitation in the API.
Check out the screenshot for more postman.
I stay overnight for a few days. Please help me....
in my code
let localUri = this.state.image; // <--- is image uri.
let filename = localUri.split('/').pop();
let match = /\.(\w+)$/.exec(filename);
let type = match ? `image/${match[1]}` : `image`;
let formData = new FormData();
formData.append('photo', { file: localUri, name: filename, type: type });
return fetch(MY_SERVER, {
method: 'POST',
body: formData,
headers: {
'Content-Type':'application/x-www-form-urlencoded'
},
}).then((response) => response.text())
.then((responseData) => {
console.log(responseData);
console.log('file',formData)
})
.done();
in error messege
I don't think I can find the key called file.
Is this an API issue?
HTTP Status 400 – Bad Request
Required request part 'file' is not present
I think the error resides in this line of code:
formData.append('photo', { file: localUri, name: filename, type: type });
Instead try to append like the following:
formData.append('file', localUri);
formData.append('name', filename);
formData.append('type', type);

How to upload local device image using Axios to S3 bucket

I need to upload an image directly to an S3 bucket. I am using react native, and react-native-image-picker to select a photo. This returns a local image uri. Here is my code right now.
ImagePicker.showImagePicker(options, response => {
var bodyFormData = new FormData(); // If I don't use FormData I end up
// uploading the json not an image
bodyFormData.append('image', {
uri: response.uri, // uri rather than data to avoid loading into memory
type: 'image/jpeg'
});
const uploadImageRequest = {
method: 'PUT',
url: presignedS3Url,
body: bodyFormData,
headers: {
'Content-Type: 'multipart/form-data'
}
};
axios(uploadImageRequest);
});
This almost works.. when I check my S3 bucket I have a file thats nearly an image. It has the following format
--Y_kogEdJ16jhDUS9qhn.KjyYACKZGEw0gO-8vPw3BcdOMIrqVtmXsdJOLPl6nKFDJmLpvj^M
content-disposition: form-data; name="image"^M
content-type: image/jpeg^M
^M
<Image data>
If I manually go in and delete the header, then I have my image! However, I need to be uploading an image directly to S3, which clients will be grabbing and expecting to already be in a proper image format.
I can make this work using response.data and decoding to a string and uploading that directly, but for the sake of memory I'd rather not do this.
Upload image to S3 from client using AJAX with presigned URL
It's been a while since you posted your question so I guess you already found a solution, but anyway... I was trying to do the same, i.e. upload an image to S3 using axios, but I just wasn't able to make it work properly. Fortunately, I found out that we can easily do the trick with plain AJAX:
const xhr = new XMLHttpRequest();
xhr.open('PUT', presignedS3Url);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log('Image successfully uploaded to S3');
} else {
console.log('Error while sending the image to S3.\nStatus:', xhr.status, "\nError text: ", xhr.responseText);
}
}
}
xhr.setRequestHeader('Content-Type', 'image/jpeg');
xhr.send({ uri: imageUri, type: 'image/jpeg', name: fileName});
This code is taken from this really useful article which borrows from this blog.

How to Fix '422 Unprocessable Entity' when sending a POST request to Redmine API?

I am trying to create a wiki page using redmine rest api.
The Authentication was succeeded, however the wiki page is not being created because of a 422 error.
The Redmine documentation says: "When trying to create or update an object with invalid or missing attribute parameters, you will get a 422 Unprocessable Entity response. That means that the object could not be created or updated."
But I can seem to find out where I have mess up. The PROBLEM CAME UP WHEN I DID THE SECOND REQUEST- "PUT REQUEST".
so we know the problem is somewhere in that section.
My guess is, it is either the file path or the content-type.
This is what I have so far....
const wordDocument="C:\Users\adasani\Desktop\practice\RedmineApi/RedmineText.txt";
creatingWikiPage_Request(wordDocument);
function creatingWikiPage_Request(wordDocument) {
axios({
method: 'post',
url: '<redmine_url>/uploads.json',
headers: { 'Content-Type': 'application/octet-stream' },
params: { 'key': '<api-key>' },
data: wordDocument
})
.then(function (response) {
console.log("succeeed---> ");
console.log(response.data.upload.token)
axios({
method: 'put',
url: '<redmine_url>/projects/Testing/wiki/WikiTesting.json',
headers: { 'Content-Type': 'application/octet-stream' },
params: { 'key': '<api-key>' },
data: {
"wiki_page": {
"text": "This is a wiki page with images, and other files.",
"uploads":[
{ "token": response.data.upload.token, "filename": "RedmineText.txt", "content-type": "text/plain" }
]
}
}
})
.then(response => {
console.log("PUT is Succeed-->>>")
console.log(response)
})
.catch(error => {
console.log("Error-->>")
console.log(error.response)
})
})
.catch(function (error) {
console.log("failed-----> ");
console.log(error.response.statusText, "-->", error.response.status);
console.log(error.response.headers)
console.log(error.message)
console.log("failed-----> ");
})
}
I am suppose to see a wiki page being created in my redmine dashboard but I am getting a 422 error.
You are sending the update request to the JSON api, i.e. <redmine_url>/projects/Testing/wiki/WikiTesting.json with Content-Type: application/octet-stream. Because of this, Redmine is unable to parse the PUTed payload since it doesn't know in what format the data is.
To solve this, you should always make sure to set the correct content type when posting data. In this case, you should set the Content-Type header to application/json when sending any JSON-formatted data to Redmine.
Note that in principal, you can send XML data to Redmine and get JSON back. The output format is determined by the file ending in the URL (.json or .xml), the format of the data sent by you is always identified by the Content-Type header.
I have similar issue while uploading multiple files to server from my flutter app; The issue is some server needs to have [] format to receive multiple files;
=> Change From
formData.files.add(MapEntry(
"videos",
await MultipartFile.fromFile(curPost.url, filename: getFileNameByFullPath(curPost.url)),
));
=> TO
formData.files.add(MapEntry(
"videos[]",
await MultipartFile.fromFile(curPost.url, filename: getFileNameByFullPath(curPost.url)),
));
Here I just make change key from videos to videos[].

Image upload in React Native (Expo), using fetch results in 400 error

I have been struggling with image upload for days.
I’m using formdata like this:
let formData = new FormData();
formData.append('file', {
uri: uri,
name: `name`,
type: `image/jpeg`,
});
uri on iOS is something like asset-library://asset/path on Android it is like content://media/external/images/media/25377.
let options = {
method: 'POST',
body: formData,
headers: {
Accept: 'application/json',
'Authorization': 'Bearer ' + token,
},
};
let response = await fetch("https://myserverurl", options)
I tried every trick reading the image as blob, removing content-type, other libraries like axios, etc…
No matter what I always get back a 400 bad file format error.
Is there something I’m missing with formdata?
(On the backend we use ASP.NET)
We have had a similar issue and were able to solve the issue the following way.
We are using a NodeJS backend (with multer) to handle the file uploads.
Expo - Mobile App Code
// extract the filetype
let fileType = uri.substring(uri.lastIndexOf(".") + 1);
let formData = new FormData();
formData.append("photo", {
uri,
name: `photo.${fileType}`,
type: `image/${fileType}`
});
let options = {
method: "POST",
body: formData,
headers: {
Accept: "application/json",
"Content-Type": "multipart/form-data"
}
};
We are executing the request with fetch(apiUrl, options).
The uri is the local file path (full URI e.g., file:///...) of the photo in our case and apiUrl is the endpoint of the server-side.
I think the issue might be with the type and format of uri in formdata. Have you tried to use the uri returned by the image picker?

Aurelia js fie upload to server

Hi am new to aurelia js , i need to upload file to server,am using autrelia js, materializecss and httpClient.fetch for api call. I dont'know how to send file to server.
view :
<input type="file" files.bind="selectedFiles" change.delegate="onSelectFile($event)">
Model :
onSelectFile(e)
{
var myurl = 'http://cdn.dmsapp.tk/file?authToken=bLNYMtfbHntfloXBuGlSPueilaHtZx&type=jpg&name=sibi.jpg&userId=7&organizationId=1&sourceType=USER_UPLOADS';
this.httpValueConverter.call_http(myurl,'POST',this.selectedFiles[],'fileupload',file_upload)
.then(data => {
console.log(data);
if(data.meta && data.meta.statusCode == 200) {
// this.index_lists = data.index.list;
}
}); }
httpservice :
return this.httpClient.fetch('http://api.dmsapp.tk/'+url,
{
method: method,
body : json(myPostData),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'authorization': this.authorization}})
.then(response => response.json());
looking for a solution.
If it's a file and you are trying to upload a particular media type,
the header 'Content-Type': 'application/x-www-form-urlencoded' does not seem right to me. Have a look at the appropriate media type here:
http://www.iana.org/assignments/media-types/media-types.xhtml
Also, you serialize data to JSON, if your data is binary you will need to change that to a byte array.
You might find some useful info here:
http://www.petermorlion.com/file-upload-with-aurelia/
Also you set a token both in your URL and your header, I'd recommend to set it in the header only.