How to send binary file multipart/form-data using post Angular? - javascript

I have tried to send a binary file with additional fields using post method and multipart/form-data.
load() {
const formData = new FormData();
formData.append('file', this.data.binary);
formData.append('reasons', this.form.get('reasons').value);
const headers = new HttpHeaders({
key: userKey,
});
const options = { headers: headers };
this.http
.post(`/api/Controller`, formData, options)
.pipe(catchError(this.handleError))
.subscribe(
() => {
alert('Success');
},
(error) => {
alert(error.Message || 'Error');
},
);
}
Where this.data.binary is:
try {
const input = event.target as HTMLInputElement;
const reader = new FileReader();
reader.onload = () => {
this.data.binary = reader.result;
};
reader.readAsArrayBuffer(input.files[0]);
} catch (e) {
alert(e);
}
In Chrome headers I see this data after submit:
FormData
file: [object ArrayBuffer]
reasons: text
How to send file as binary correct?
I have trird also this:
formData.append('file', new Blob(this.data.binary));

don't use the FileReader to read it as binary.
Just use the FormData and append it directly
const formData = new FormData()
formData.append('file', input.files[0])
beside, readAsBinaryString is a bad practices and should use arrayBuffer instead when dealing with binary
I would also suggest that you do something like new FormData(formElement) so that you don't have to append/set every single field that is needed.

Related

multipart/form-data not being automatically set with axios in React Native

When attempting to upload a file to Amazon S3 using axios, I have been encountering a very strange issue. Normally, in a web browser, when FormData has binary data in it, the Content-Type header automatically gets set to multipart/form-data; boundary=<some random string>. However, I have been completely unable to achieve that in React Native (testing on an iOS device). The Content-Type is automatically set to application/json, and thus not being detected as a correctly formatted body when uploading to Amazon S3. I have tried specifying a blob in the file parameter in FormData instead of the URI to the file as well to no avail. I have appended my code below, any advice would be very much appreciated.
const uploadFileToS3 = (
presignedPostData,
file) => {
// create a form obj
const formData = new FormData();
// append the fields in presignedPostData in formData
Object.keys(presignedPostData.fields).forEach(
key => {
formData.append(
key,
presignedPostData.fields[key],
);
},
);
// append the file and uplaod
const getBlob = async () => {
const img_url = previewPath;
let result = await fetch(img_url);
const blob = await result.blob();
formData.append('Content-Type', 'image/jpeg');
formData.append('file', {
uri: previewPath,
type: 'image/jpeg',
name: 'test.jpeg',
});
console.log(formData, 'wild');
// post the data on the s3 url
axios
.post(presignedPostData.url, formData)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error.response);
});
};
getBlob();
};

API doesn't receive file + text posted through a FormData

I want to upload an file with a text to my api. The Api says that the schema is not JSON but multipart. So I included the information(image and text) in a FormData in order to post it to the api afterwards.
This looks like this:
My class model:
export class FormData {
image: any;
category: string;
constructor(args){
this.image = args.image;
this.category = args.category;
}
}
api call:
apiSubmit() {
const formData = new FormData(this.categoryForm.value);
console.log(formData);
this.http.post<any>(this.url, formData, httpOptions).subscribe(
(res) => console.log(res),
);
}
The values are actually assigned to formData, so FormData has both values the file and the text stored.
But somehow the data doesn't find its was to the api properly:( when I want to post, the api spits out the following error.
Do I somehow have to singely show the api which part of the FormData is the file and which part is the string? And if yes how would I do that?
this maybe work. You must send a Blob type.
In this example I'll send a base64 file, this is a better option.
export class FileData {
contentBase64: string;
mimeType: string;
name: string;
}
apiSubmit() {
const formData = new FormData();
const blob = new Blob([file.contentBase64], { type: file.mimeType });
formData.append('file', blob, file.name);
this.http.post<any>(this.url, formData, httpOptions).subscribe(
(res) => console.log(res),
);
}

Formdata is blank at the backend

I pass image data by appending with formdata in reactjs
This is the handler for this
handleUserImage(e) {
const input = e.target
if (input.files && input.files[0]) {
const reader = new FileReader()
reader.onload = (r) => {
const formdata = new FormData()
formdata.append('photos', input.files[0])
formdata.append('fileName', input.files[0].name)
this.props.uploadImage({ image: formdata })
}
reader.readAsDataURL(input.files[0])
}
}
and when I console it to backend it looks like blank object
{ image: {} }
Then how can I pass formdata and upload the image
Edit : Upload image api call
export const uploadImage = (data) => {
console.log(data)
return fetch(`http://hostName:3001/town/image`, {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data'
},
body: data
})
.then((res) => {
return res.json()
})
.then((payload) => {
console.log(payload)
return payload
}).catch((error) => {
throw error
})
}
when I console it to backend it looks like blank object
This is normal.
headers: {
'Content-Type': 'multipart/form-data'
},
Multipart form data MIME types need to have a parameter to describe the boundary marker (so parsers know where one field ends and the next begins).
Yours is missing it. What's more, there is no way for you to know what it will be.
Don't override the Content-Type header, allow fetch to generate it from the FormData object. Remove the code I quoted entirely.
Why use FileReader, upload it as base64 and append file name separately?
you can just do
handleUserImage (evt) {
const file = evt.target.files[0]
if (file) {
const formdata = new FormData()
formdata.append('photos', file)
this.props.uploadImage({ image: formdata })
}
}
You save a few bytes,
avoid unnecessary decode & encode calculations
runs faster
saves ~3x bandwidth
FormData.append(name, value, filename)
name
The name of the field whose data is contained in value.
value
The field's value. This can be a USVString or Blob (including subclasses such as File).
filename Optional
The filename reported to the server (a USVString), when a Blob or File is passed as the second parameter. The default filename for Blob objects is "blob". The default filename for File objects is the file's filename.
-- MDN - FormData.append()

Read blob file in base64 and upload on the server

When I drop a file in the upload area, the React-dropzone returns an object such as:
let picture = [
{
"rawFile": {
"preview": "blob:http://localhost:3000/ff851b03-b2c0-4212-9240-8d07057ad47d"
},
"src": "blob:http://localhost:3000/ff851b03-b2c0-4212-9240-8d07057ad47d",
"title": "1397-01-20 13.43.24.jpg"
}
]
I read this link and try to upload the file: React dropzone, how to upload image?
But I think the file will not be sent.
This is my code:
let formData = new FormData();
formData.append('file', picture[0]);
fetch('http://localhost:8000/api/media', {
method: 'POST',
body: formData
});
If this method is not correct, How to send the file to the server side and receive it on the server side?
On the server side, I'm using Hapij.
I solved the problem. I write the answer because anybody didn't answer this question.
In the client side, I use the FileReader API to read the BLOB data and convert it to base64 readable format. I write a function to convert blob to base64 and send fileName and base64 to the server side.
const convertFileToBase64 = file => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file.rawFile);
reader.onload = () => resolve({
fileName: file.title,
base64: reader.result
});
reader.onerror = reject;
});
On the server side, I write the buffer to the file by this function:
const fs = require("fs");
const Boom = require('boom');
function convertBase64ToFile(file) {
let base64Data = file.base64.split(',')[1];
fs.writeFile(`${__dirname}/../../uploads/${file.fileName}`, base64Data, 'base64', function(err) {
return Boom.badData(err);
});
// Other actions...
}
This method works for me perfectly.

Upload file in angular2: Body (FormData) empty

I'm trying to upload a picture with Angular2 to my REST Service (Loopback).
The Loopback service works (tested with Postman) and accepts files with the x-www-form-urlencoded header.
Here's a simplified service method that sends the POST request:
public uploadFile(url : string, file: File): Observable<any> {
let headers: Headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
let formData = new FormData();
formData.append('file', file);
let options: RequestOptionsArgs = { headers: headers };
return this.http.post(url, formData, options)
.map((res: any) => (res.text() != "" ? res.json() : {}));
}
Note that I've set the header to application/x-www-form-urlencoded and send the formData containing the file in the body.
In Angular, up until the point where I http.post the request, the formData is populated with the file, the file content is present, everyting's fine:
Data before Request
But in the request, the body is an empty object {}:
Request
I assume, Angular is trying to do JSON.stringify(formData), at least, when I try this, I also get "{}" as output.
I've seen plenty of posts doing exactly the same (http.post(url, formData)). So what am I missing?
Just remove headers.append('Content-Type', 'multipart/form-data'); can solve problem.
See here
2017-08-24
From this How to inspect FormData? SO answer and this MDN documentation outputing FormData in the console just results in a {}.
FormData can directly be used in a for ... of structure, instead of entries(): for (var p of myFormData) is equivalent to for (var p of myFormData.entries()).
There is another solution is to use base64 and convert it in back-end side:
`
var reader = new FileReader();
reader.readAsDataURL(file);
let res;
reader.onload = function () {
let headers = new Headers();
headers.append("Content-type","application/x-www-form-urlencoded");
headers.append('Accept', 'application/json');
let options = new RequestOptions({ headers: headers });
return this.http.post(config.serverUrl+"/index.php",
{
"file":reader.result}, options)
.toPromise()
.then(this.extractData)
.catch(this.handleError);
}
};
reader.onerror = function (error) {
console.log('Error: ', error);
};`
In my case i used formData.set() instead of formData.append()
please see example below :
UploadFile(fileToUpload: File): Observable<boolean> {
const endpoint = 'api/image/upload';
var formData = new FormData();
formData.set('file', fileToUpload);
return this._http
.post(endpoint, formData)
.map(() => { return true; })
.catch((e) => this.handleError(e));
}

Categories

Resources