I read all over but couldn't find the answer.
When I use FormData(), it returns status 404 bad request.
However, if I pass the data (hardcoded) as in const requestBody (example below), it works perfectly.
This is my code:
var formData = new FormData();
formData.append("nickname", "johxns");
formData.append("password", "john_password");
formData.append("email", "john#server.com");
// If I do it this way, and assign this to body inside fetch, it works perfectly
// const requestBody = '{"nickname": "johxns","password":"john_password","email":"john#server.com"}';
fetch("http://localhost:5000/create_user", {
// if instead of formData, I assign requestBody to body, it works!
body: formData,
headers: {
"Content-Type": "application/json"
},
method: "POST"
}).then(function(response) {
return response.text();
}).then(function(data){
console.log('data', data);
}).catch(function(err){
console.err(err);
});
I already tried with URLSearchParams, but still couldn't make it work.
Thanks.
You shouldn't set the Content-Type header to application/json if you're not sending json. According to this answer, you don't need to set the Content-Type header.
body data type must match "Content-Type" header
Using Fetch
You should either send json data if you set Content-Type to application/json or not set any Content-Type if using FormData API since the fetch function is able to determine the correct Content-Type.
See here for more informations.
Related
I want to set _boundry in my header.
First, I dispatch the form data:
//component.js
const form = new FormData();
form.append('email', 'eray#serviceUser.com')
form.append('password', '12121212')
dispatch(FetchLogin.action(form))
Second, I prepare api call;
//loginService.js
import api from '#/Services'
export default async form => {
const response = await api.post('user/login/', form)
return response.data
}
Third, I make api call;
//Services/index.js
import axios from 'axios'
import { Config } from '#/Config'
const instance = axios.create({
baseURL: Config.API_URL,
headers: {
'Content-Type': `multipart/form-data; boundary=${form._boundary}`, //Cannot access form here
},
timeout: 3000,
})
instance.interceptors.response.use(
response => response,
({ message, response: { data, status } }) => {
return handleError({ message, data, status })
},
)
export default instance
I want to access form data within to axios instance to be able to use form._boundry in headers.
How can I pass form data from loginService.js to Services/index.js?
This question seems to come up often enough yet I cannot seem to find a canonical answer so here goes...
When performing AJAX requests from a browser (via fetch or XMLHttpRequest), the runtime knows what to do for certain request body formats and will automatically set the appropriate Content-type header
If the request body is a FormData instance, the Content-type will be set to multipart/form-data and will also include the appropriate mime boundary tokens from the data instance.
All of these examples will post the data as multipart/form-data with appropriate mime boundary tokens
const body = new FormData();
// attach files and other fields
body.append("file", fileInput.files[0]);
body.append("foo", "foo");
body.append("bar", "bar");
// fetch
fetch(url, { method: "POST", body });
// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.send(body);
// Axios
axios.post(url, body);
If the request body is a URLSearchParams instance, the Content-type will be set to application/x-www-form-urlencoded
All of these examples will post the data as application/x-www-form-urlencoded
const body = new URLSearchParams({ foo: "foo", bar: "bar" });
// serialises to "foo=foo&bar=bar"
// fetch
fetch(url, { method: "POST", body });
// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.send(body);
// Axios
axios.post(url, body);
You only need to manually set the content-type if you intend to send string data in a particular format, eg text/xml, application/json, etc since the runtime cannot infer the type from the data.
const body = JSON.stringify({ foo: "foo", bar: "bar" });
// fetch
fetch(url, {
method: "POST",
headers: {
"content-type": "application/json",
},
body
});
// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.setRequestHeader("content-type", "application/json");
xhr.send(body);
On Axios
Axios will automatically stringify JavaScript data structures passed into the data parameter and set the Content-type header to application/json so you only need minimal configuration when dealing with JSON APIs
// no extra headers, no JSON.stringify()
axios.post(url, { foo: "foo", bar: "bar" })
Under the hood, Axios uses XMLHttpRequest so the specifications for FormData and URLSearchParams also apply.
Axios v0.27.1 is broken
This specific version of Axios is unable to make a proper request with FormData. Do not use it!
Axios v1.0.0+ is broken
This is verging into my own opinion but every Axios release post v1.0.0 has been fundamentally broken in one way or another. I simply cannot recommend anyone use it for any reason.
Much better alternatives are:
The Fetch API (also available in Node v18+)
got for Node.js
ky for browsers
NodeJS
When using Axios from the backend, it will not infer Content-type headers from FormData instances. You can work around this using a request interceptor.
axios.interceptors.request.use(config => {
if (config.data instanceof FormData) {
Object.assign(config.headers, config.data.getHeaders());
}
return config;
}, null, { synchronous: true });
or simply merge in the headers when making a request
axios.post(url, body, {
headers: {
"X-Any-Other-Headers": "value",
...body.getHeaders(),
},
});
See https://github.com/axios/axios#form-data
On jQuery $.ajax()
jQuery's $.ajax() method (and convenience methods like $.post()) default to sending request body payloads as application/x-www-form-urlencoded. JavaScript data structures will be automatically serialised using jQuery.param() unless told not to. If you want the browser to automatically set the Content-type header based on the body format, you also need to configure that in the options
const body = new FormData()
body.append("foo", "foo")
body.append("bar", "bar")
$.ajax({
url,
method: "POST",
data: body,
contentType: false, // let the browser figure it out
processData: false // don't attempt to serialise data
})
I want to set _boundry in my header.
First, I dispatch the form data:
//component.js
const form = new FormData();
form.append('email', 'eray#serviceUser.com')
form.append('password', '12121212')
dispatch(FetchLogin.action(form))
Second, I prepare api call;
//loginService.js
import api from '#/Services'
export default async form => {
const response = await api.post('user/login/', form)
return response.data
}
Third, I make api call;
//Services/index.js
import axios from 'axios'
import { Config } from '#/Config'
const instance = axios.create({
baseURL: Config.API_URL,
headers: {
'Content-Type': `multipart/form-data; boundary=${form._boundary}`, //Cannot access form here
},
timeout: 3000,
})
instance.interceptors.response.use(
response => response,
({ message, response: { data, status } }) => {
return handleError({ message, data, status })
},
)
export default instance
I want to access form data within to axios instance to be able to use form._boundry in headers.
How can I pass form data from loginService.js to Services/index.js?
This question seems to come up often enough yet I cannot seem to find a canonical answer so here goes...
When performing AJAX requests from a browser (via fetch or XMLHttpRequest), the runtime knows what to do for certain request body formats and will automatically set the appropriate Content-type header
If the request body is a FormData instance, the Content-type will be set to multipart/form-data and will also include the appropriate mime boundary tokens from the data instance.
All of these examples will post the data as multipart/form-data with appropriate mime boundary tokens
const body = new FormData();
// attach files and other fields
body.append("file", fileInput.files[0]);
body.append("foo", "foo");
body.append("bar", "bar");
// fetch
fetch(url, { method: "POST", body });
// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.send(body);
// Axios
axios.post(url, body);
If the request body is a URLSearchParams instance, the Content-type will be set to application/x-www-form-urlencoded
All of these examples will post the data as application/x-www-form-urlencoded
const body = new URLSearchParams({ foo: "foo", bar: "bar" });
// serialises to "foo=foo&bar=bar"
// fetch
fetch(url, { method: "POST", body });
// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.send(body);
// Axios
axios.post(url, body);
You only need to manually set the content-type if you intend to send string data in a particular format, eg text/xml, application/json, etc since the runtime cannot infer the type from the data.
const body = JSON.stringify({ foo: "foo", bar: "bar" });
// fetch
fetch(url, {
method: "POST",
headers: {
"content-type": "application/json",
},
body
});
// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.setRequestHeader("content-type", "application/json");
xhr.send(body);
On Axios
Axios will automatically stringify JavaScript data structures passed into the data parameter and set the Content-type header to application/json so you only need minimal configuration when dealing with JSON APIs
// no extra headers, no JSON.stringify()
axios.post(url, { foo: "foo", bar: "bar" })
Under the hood, Axios uses XMLHttpRequest so the specifications for FormData and URLSearchParams also apply.
Axios v0.27.1 is broken
This specific version of Axios is unable to make a proper request with FormData. Do not use it!
Axios v1.0.0+ is broken
This is verging into my own opinion but every Axios release post v1.0.0 has been fundamentally broken in one way or another. I simply cannot recommend anyone use it for any reason.
Much better alternatives are:
The Fetch API (also available in Node v18+)
got for Node.js
ky for browsers
NodeJS
When using Axios from the backend, it will not infer Content-type headers from FormData instances. You can work around this using a request interceptor.
axios.interceptors.request.use(config => {
if (config.data instanceof FormData) {
Object.assign(config.headers, config.data.getHeaders());
}
return config;
}, null, { synchronous: true });
or simply merge in the headers when making a request
axios.post(url, body, {
headers: {
"X-Any-Other-Headers": "value",
...body.getHeaders(),
},
});
See https://github.com/axios/axios#form-data
On jQuery $.ajax()
jQuery's $.ajax() method (and convenience methods like $.post()) default to sending request body payloads as application/x-www-form-urlencoded. JavaScript data structures will be automatically serialised using jQuery.param() unless told not to. If you want the browser to automatically set the Content-type header based on the body format, you also need to configure that in the options
const body = new FormData()
body.append("foo", "foo")
body.append("bar", "bar")
$.ajax({
url,
method: "POST",
data: body,
contentType: false, // let the browser figure it out
processData: false // don't attempt to serialise data
})
I m using react js app and I try to post data to my api , but I got undefined insert for one time .
instead of 'url' I have working url.
this is my post method's code:
senddata(){
if(!this.formvalidation())
{
try{
let resulte = fetch('url',{
method:'post',
mode:'no-cors',
headers:{
'Accept':'application/json',
'Content-type': 'application/json'
},
body:JSON.stringify({
ID:this.state.code,
Blod:this.state.blod,
Allergic:this.state.allergicdescription,
Chronic:this.state.chronic_description
})
});
alert("post");
}catch(e){
alert("not post")
}
}
}
thanks.
You said mode:'no-cors' so any attempt to do anything which requires permission from CORS will fail silently.
Setting 'Content-type': 'application/json' requires permission from CORS.
Presumably, your server side code is not parsing the request body as JSON since the Content-Type header doesn't say it is JSON.
Since there is no parsed data, all the properties you want to read from the JSON will be undefined.
Don't use mode:'no-cors' if you want to POST JSON.
I am posting request to my backend server using fetch api in React js
const formData = new FormData();
formData.append("image", file);
formData.append("userId", currentUser.id);
formData.append("sliderNumber", sliderNumber);
const myHeaders = new Headers();
myHeaders.append("Content-Type", file.type);
myHeaders.append("Aceess-Control-Allow-Origin", "*");
fetch("http://localhost:4000/upload/slide-image", {
method: "POST",
headers: myHeaders,
mode: "no-cors",
body: formData
})
.then(response => response)
.then(data => console.log("Printing data: ", data));
};
In elixir backend
def upload(conn, params) do
# uploading code
#send response to the client with amazon s3 image url
send_resp(conn, 200, image_url)
end
but Response object from fetch api is empty
Response {
body: null
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 0
statusText: ""
type: "opaque"
url: ""
}
And it doesn't change when I respond with status code 400.
It seems like fetch api is not building Reponse object correctly in some point. Because I can find correct status code and response body in browser network tab. But Response object doesn't hold response from backend server.
Any idea?
If you are expecting a text response from your server, then on your first .then(.. you should do like:
fetch("http://localhost:4000/upload/slide-image", {
method: "POST",
headers: myHeaders,
mode: "no-cors",
body: formData
})
.then(response => response.text()) // <---
.then(data => console.log("Printing data: ", data));
fetch returns a Promise that resolves to a Response. When you use .text() at this stage, what you actually do is to take the Response stream, read it to completion and return a promise that will resolve with a text.
Aside from that, you also use mode: "no-cors" (as other users mentioned on their answers) that limits you in many ways. For example, even if you follow my instructions above, you will get an empty string, even if you are trying to return something from your server. And that will be because of this mode.
You can find more details about it here, under bullet no-cors.
Your Content-Type is wrong. When sending files along with other data, the Content-Type should still be multipart/form-data.
mode: "no-cors",
You set the mode to no-cors, so the response is Opaque, which means you can't see inside it.
Don't do that if you need to read the response.
Asides:
myHeaders.append("Content-Type", file.type);
That's the wrong content-type for a form data object. Don't set the content-type. The fetch API will set the correct one automatically.
myHeaders.append("Aceess-Control-Allow-Origin", "*");
Access-Control-Allow-Origin, which you misspelt, is a response header, not a request header.
.then(response => response)
Returning the response unchanged is rather pointless. You probably want response.text() if you are getting a plain URL back.
The accepted answer solved my pinpoint.
if you are expecting a JSON object from the backend, use
.then((response) => response.json())
For some reason, I can't get file transfers to work via fetch. My code is really simple:
export function updateProfilePicture(apiKey, userID, picture) {
let data = new FormData();
data.append('picture', picture);
return fetch(`${API_URL}/v1/${ROOT}/update_profile_picture/${userID}`,{
headers: {'Authorization': `Token token=${apiKey}`},
method: 'POST',
data: data
}).then(response => response.json());
}
However, the resulting request does not seem to include any file whatsoever. Am I missing something? In the above example, picture is instance an of File
There could be two reasons:
data field in Fetch API is called body. Use this instead of data property.
(optional) You need to add another header: 'Content-Type', 'multipart/form-data'
Read more about Fetch API:
https://developers.google.com/web/updates/2015/03/introduction-to-fetch?hl=en
https://developer.mozilla.org/en/docs/Web/API/Fetch_API
Fetch polyfill