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()
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.
fetch(url, {
method: "POST",
headers: {
"Content-type": "application/json",
},
body: JSON.stringify({ foo: "foo", bar: "bar" })
})
On Axios
Axios provides defaults of Accept: application/json
and Content-type: application/json
for POST
, PUT
and PATCH
requests. It will also automatically stringify JavaScript data structures passed into the data
parameter 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.
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;
});
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
})