so i want to upload an image to a server which doesn't accept json payloads, but rather formData.
What i'm doing is
var bodyFormData = new FormData();
bodyFormData.set("access_token", globalState.access_token);
bodyFormData.set("listing_id", 2);
bodyFormData.append("image", Cookies.get("listingCover"));
but after this if i console.log(bodyFormData) it returns an empty object? Instead if i console.log(...bodyFormData) it returns 3 saperate arrays of each formdata that i set above. I want to be able to send it as bodyFormData in the body of the request like shown below. How do i do that?
axios({
method,
url: url,
data: bodyFormData,
headers: { "Content-Type": "multipart/form-data" },
})
Use FormData.entries() to console.log to see whats stored in your formData
You can not simply console.log(bodyFormData) it will NOT return anything.
Run snippet below.
var bodyFormData = new FormData();
bodyFormData.set("access_token", 'globalState.access_token');
bodyFormData.set("listing_id", 2);
bodyFormData.append("image", 'Cookies.get("listingCover")');
//Loop througt formData
for (var data of bodyFormData.entries()) {
console.log(data[0]+ ', ' + data[1]);
}
You do no have any method when you are doing axios You need to set your method to post like below to send your bodyFormData
Edit: Working Demo: https://jsfiddle.net/mxkLejrf/
=> In the demo you can see dev tools -> network the bodyFormData is being sent via POST
axios({
method: 'post',
url: 'someEndPointUrl',
data: bodyFormData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(function(response) {
// success
console.log(response);
})
.catch(function(response) {
// error
console.log(response);
});
Related
I have an API endpoint that lets the client post their csv to our server then post it to someone else server. I have done our server part which save uploaded file to our server, but I can't get the other part done. I keep getting error { message: 'File not found', code: 400 } which may mean the file never reach the server. I'm using axios as an agent, does anyone know how to get this done? Thanks.
// file = uploaded file
const form_data = new FormData();
form_data.append("file", fs.createReadStream(file.path));
const request_config = {
method: "post",
url: url,
headers: {
"Authorization": "Bearer " + access_token,
"Content-Type": "multipart/form-data"
},
data: form_data
};
return axios(request_config);
Update
As axios doc states as below and the API I'm trying to call requires a file
// data is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', and 'PATCH'
// When no transformRequest is set, must be of one of the following types:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - Browser only: FormData, File, Blob
// - Node only: Stream, Buffer
Is there any way to make axios send a file as a whole? Thanks.
The 2 oldest answers did not work for me. This, however, did the trick:
const FormData = require('form-data'); // npm install --save form-data
const form = new FormData();
form.append('file', fs.createReadStream(file.path));
const request_config = {
headers: {
'Authorization': `Bearer ${access_token}`,
...form.getHeaders()
}
};
return axios.post(url, form, request_config);
form.getHeaders() returns an Object with the content-type as well as the boundary.
For example:
{ "content-type": "multipart/form-data; boundary=-------------------0123456789" }
I'm thinking the createReadStream is your issue because its async. try this.
Since createReadStream extends the event emitter, we can "listen" for when it finishes/ends.
var newFile = fs.createReadStream(file.path);
// personally I'd function out the inner body here and just call
// to the function and pass in the newFile
newFile.on('end', function() {
const form_data = new FormData();
form_data.append("file", newFile, "filename.ext");
const request_config = {
method: "post",
url: url,
headers: {
"Authorization": "Bearer " + access_token,
"Content-Type": "multipart/form-data"
},
data: form_data
};
return axios(request_config);
});
This is what you really need:
const form_data = new FormData();
form_data.append("file", fs.createReadStream(file.path));
const request_config = {
headers: {
"Authorization": "Bearer " + access_token,
"Content-Type": "multipart/form-data"
},
data: form_data
};
return axios
.post(url, form_data, request_config);
In my case, fs.createReadStream(file.path) did not work.
I had to use buffer instead.
const form = new FormData();
form.append('file', fs.readFileSync(filePath), fileName);
const config = {
headers: {
Authorization: `Bearer ${auth.access_token}`,
...form.getHeaders(),
},
};
axios.post(api, form.getBuffer(), config);
I have made an interceptor you can connect to axios to handle this case in node: axios-form-data. Any feedback would be welcome.
npm i axios-form-data
example:
import axiosFormData from 'axios-form-data';
import axios from 'axios';
// connect axiosFormData interceptor to axios
axios.interceptors.request.use(axiosFormData);
// send request with a file in it, it automatically becomes form-data
const response = await axios.request({
method: 'POST',
url: 'http://httpbin.org/post',
data: {
nonfile: 'Non-file value',
// if there is at least one streamable value, the interceptor wraps the data into FormData
file: createReadStream('somefile'),
},
});
// response should show "files" with file content, "form" with other values
// and multipart/form-data with random boundary as request header
console.log(response.data);
I had a same issue, I had a "pdf-creator-service" for generate PDF document from html.
I use mustache template engine for create HTML document - https://www.npmjs.com/package/mustache
Mustache.render function returns html as a string what do I need to do to pass it to the pdf-generator-service ? So lets see my suggestion bellow
//...
async function getPdfDoc(props: {foo: string, bar: string}): Promise<Buffer> {
const temlateFile = readFileSync(joinPath(process.cwd(), 'file.html'))
mustache.render(temlateFile, props)
const readableStream = this.getReadableStreamFromString(htmlString)
const formData = new FormData() // from 'form-data'
formData.append('file', options.file, { filename: options.fileName })
const formHeaders = formData.getHeaders()
return await axios.send<Buffer>(
{
method: 'POST',
url: 'https://pdf-generator-service-url/pdf',
data: formData,
headers: {
...formHeaders,
},
responseType: 'arraybuffer', // ! important
},
)
}
getReadableStreamFromString(str: string): Readable {
const bufferHtmlString = Buffer.from(str)
const readableStream = new Readable() // from 'stream'
readableStream._read = () => null // workaround error
readableStream.push(bufferHtmlString)
readableStream.push(null) // mark end of stream
return readableStream
}
For anyone who wants to upload files from their local filesystem (actually from anywhere with the right streams architecture) with axios and doesn't want to use any external packages (like form-data).
Just create a readable stream and plug it right into axios request function like so:
await axios.put(
url,
fs.createReadStream(path_to_file)
)
Axios accepts data argument of type Stream in node context.
Works fine for me at least in Node v.16.13.1 and with axios v.0.27.2
I have an API endpoint that lets the client post their csv to our server then post it to someone else server. I have done our server part which save uploaded file to our server, but I can't get the other part done. I keep getting error { message: 'File not found', code: 400 } which may mean the file never reach the server. I'm using axios as an agent, does anyone know how to get this done? Thanks.
// file = uploaded file
const form_data = new FormData();
form_data.append("file", fs.createReadStream(file.path));
const request_config = {
method: "post",
url: url,
headers: {
"Authorization": "Bearer " + access_token,
"Content-Type": "multipart/form-data"
},
data: form_data
};
return axios(request_config);
Update
As axios doc states as below and the API I'm trying to call requires a file
// data is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', and 'PATCH'
// When no transformRequest is set, must be of one of the following types:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - Browser only: FormData, File, Blob
// - Node only: Stream, Buffer
Is there any way to make axios send a file as a whole? Thanks.
The 2 oldest answers did not work for me. This, however, did the trick:
const FormData = require('form-data'); // npm install --save form-data
const form = new FormData();
form.append('file', fs.createReadStream(file.path));
const request_config = {
headers: {
'Authorization': `Bearer ${access_token}`,
...form.getHeaders()
}
};
return axios.post(url, form, request_config);
form.getHeaders() returns an Object with the content-type as well as the boundary.
For example:
{ "content-type": "multipart/form-data; boundary=-------------------0123456789" }
I'm thinking the createReadStream is your issue because its async. try this.
Since createReadStream extends the event emitter, we can "listen" for when it finishes/ends.
var newFile = fs.createReadStream(file.path);
// personally I'd function out the inner body here and just call
// to the function and pass in the newFile
newFile.on('end', function() {
const form_data = new FormData();
form_data.append("file", newFile, "filename.ext");
const request_config = {
method: "post",
url: url,
headers: {
"Authorization": "Bearer " + access_token,
"Content-Type": "multipart/form-data"
},
data: form_data
};
return axios(request_config);
});
This is what you really need:
const form_data = new FormData();
form_data.append("file", fs.createReadStream(file.path));
const request_config = {
headers: {
"Authorization": "Bearer " + access_token,
"Content-Type": "multipart/form-data"
},
data: form_data
};
return axios
.post(url, form_data, request_config);
In my case, fs.createReadStream(file.path) did not work.
I had to use buffer instead.
const form = new FormData();
form.append('file', fs.readFileSync(filePath), fileName);
const config = {
headers: {
Authorization: `Bearer ${auth.access_token}`,
...form.getHeaders(),
},
};
axios.post(api, form.getBuffer(), config);
I have made an interceptor you can connect to axios to handle this case in node: axios-form-data. Any feedback would be welcome.
npm i axios-form-data
example:
import axiosFormData from 'axios-form-data';
import axios from 'axios';
// connect axiosFormData interceptor to axios
axios.interceptors.request.use(axiosFormData);
// send request with a file in it, it automatically becomes form-data
const response = await axios.request({
method: 'POST',
url: 'http://httpbin.org/post',
data: {
nonfile: 'Non-file value',
// if there is at least one streamable value, the interceptor wraps the data into FormData
file: createReadStream('somefile'),
},
});
// response should show "files" with file content, "form" with other values
// and multipart/form-data with random boundary as request header
console.log(response.data);
I had a same issue, I had a "pdf-creator-service" for generate PDF document from html.
I use mustache template engine for create HTML document - https://www.npmjs.com/package/mustache
Mustache.render function returns html as a string what do I need to do to pass it to the pdf-generator-service ? So lets see my suggestion bellow
//...
async function getPdfDoc(props: {foo: string, bar: string}): Promise<Buffer> {
const temlateFile = readFileSync(joinPath(process.cwd(), 'file.html'))
mustache.render(temlateFile, props)
const readableStream = this.getReadableStreamFromString(htmlString)
const formData = new FormData() // from 'form-data'
formData.append('file', options.file, { filename: options.fileName })
const formHeaders = formData.getHeaders()
return await axios.send<Buffer>(
{
method: 'POST',
url: 'https://pdf-generator-service-url/pdf',
data: formData,
headers: {
...formHeaders,
},
responseType: 'arraybuffer', // ! important
},
)
}
getReadableStreamFromString(str: string): Readable {
const bufferHtmlString = Buffer.from(str)
const readableStream = new Readable() // from 'stream'
readableStream._read = () => null // workaround error
readableStream.push(bufferHtmlString)
readableStream.push(null) // mark end of stream
return readableStream
}
For anyone who wants to upload files from their local filesystem (actually from anywhere with the right streams architecture) with axios and doesn't want to use any external packages (like form-data).
Just create a readable stream and plug it right into axios request function like so:
await axios.put(
url,
fs.createReadStream(path_to_file)
)
Axios accepts data argument of type Stream in node context.
Works fine for me at least in Node v.16.13.1 and with axios v.0.27.2
I've spent hours trying to figure out how to format my JSON in Vue.js to send it this way:
At the moment I'm trying to do it with a FormData() object, but the result is still just:
My function looks like this:
register () {
var bodyFormData = new FormData();
bodyFormData.append('firstname', 'Coca');
bodyFormData.append('lastname', 'Cola')
console.log(jsonData)
axios({
method: 'post',
url: 'backend/index.php?action=createUser',
data: bodyFormData,
headers: {'Content-Type': 'multipart/form-data' }
})
.then(function (response) {
//handle success
console.log(response);
})
.catch(function (response) {
//handle error
console.log(response);
});
}
I've achieved the result on the first picture through jQuery AJAX calls, is this also possible with Axios in Vue?
You can use the JSON.stringify method and append your object to your form data.
bodyFormData.append('data', JSON.stringify(jsonData));
You are explicitly using Content-Type: multipart/form-data and sending form data for your data parameter. To send JSON, set data to the object you want to serialize as JSON, and use application/json as your content-type.
async register () {
try {
const response = await axios({
method: 'post',
url: 'backend/index.php?action=createUser',
data: { firstname: 'Coca', lastname: 'Cola' },
headers: {'Content-Type': 'application/json' }
});
//handle success
console.log(response);
} catch (err) {
//handle error
console.log(err);
}
}
Thanks for your answers, I actually had to make a FormData and populate it with stringified JSON data.
I am able to upload an image perfectly fine using the native fetch POST:
let formData = new FormData();
formData.append('file', event.target.files[0]);
console.log(event.target.files[0]);
fetch('http://localhost:8080/file/upload', {
method: 'POST',
headers:{
'Authorization': 'Bearer ' + JWT
},
body:formData
}).then(response => console.log(response));
However, when I try this using Angular's HttpClient, the request fails since the 'Content-Type': 'multipart/form-data' is not added.
My Angular code:
The file where I'm calling the service:
this.fileSaverService.uploadImage(event.target.files[0]).subscribe(
(data)=>{
console.log(data);
},
(error) => {
console.log(error);
}
);
The fileSaverService:
uploadImage(fileToUpload) {
const endpoint = 'http://localhost:8080/file/upload';
const formData: FormData = new FormData();
formData.append('file', fileToUpload);
return this.api
.post(endpoint, formData, { headers: {'Content-Type': 'multipart/form-data'} });
}
The this.api:
post(endpoint: string, body: any, reqOpts: any = {}) {
reqOpts.headers = this.handleHeaders(reqOpts.headers);
return this.http.post(endpoint, JSON.stringify(body), reqOpts);
}
If I add the header manually when using HttpClient, I get this header without the boundary:
However the native fetch adds this header automatically with the boundary if I don't specify a header and this works perfectly:
What are my options here?
There are two problems with the code in your question:
By setting Content-Type to multipart/form-data yourself, the serialisation of your FormData will not result in the correct header with boundaries being set behind the scenes.
In your post function, you have JSON.stringify(body), which is converting your FormData object into a JSON string. After doing this, you're simply attempting to POST a string rather than a complete FormData object.
I use fetch to upload images in react,my code is like below:
let formData = new FormData();
let file = {uri: imgdata, type: 'multipart/form-data', name: '2_resources.jpg'};
formData.append("name", "name");
formData.append("mobile", "18381307123");
formData.append("content", "123654");
formData.append("resources", file,"2_resources.jpg");//mind this line
fetch(Config.report,
{
mode: 'cors',
method: "POST",
body: formData
})
.then(res => res.json())
.then((data) => {
console.log(data)
}
).catch((err) => {
console.log(err)
}
);
but,run it I get the request :
I have look for FormData API document on https://developer.mozilla.org/en-US/docs/Web/API/FormData
it have write below:
and the fetch used is :"isomorphic-fetch": "^2.2.1"
what should I do to use fetch upload images? thanks.
You are adding the file to the FormData object incorrectly. isomorphic-fetch wraps github's fetch polyfill. Looking at their docs shows that it should be:
handleFileUpload(event) {
var formData = new FormData();
formData.append('fileName', event.target.files[0]);
fetch('http://your-domain/upload',
{
mode: 'cors',
method: 'POST',
body: formData
}).then(function (response) {
console.log('response: ', response);
});
}
The field name on the server will be whatever you use as the key when appending formData. In the above example it will be 'fileName'. I also don't think you need to set the content-type and file name yourself. It should get set automatically.
In the above example, 'event' is the event fired from the input tag when the user upload the file:
<input type="file" onChange={this.handleFileUpload}/>