Big boy
Big boy

Reputation: 1741

Axios not respecting Content-Type header

This is my axios configuration:

import axios from "axios"

const axiosApi = axios.create({
  baseURL: import.meta.env.VITE_API_URL
})

const requestInterceptor = config => {
  config.headers['Content-Type'] = 'application/json';
  config.headers['Accept'] = 'application/json';
  config.headers['X-Client'] = 'React';
  return config;
}

axiosApi.interceptors.request.use(requestInterceptor);

const get = async (url) => {
  return await
    axiosApi.get(url, {
      crossDomain: true
    }).then(response => {
      return response?.data;
    })
}

const post = async (url, data) => {
  return await axiosApi
    .post(url, Array.isArray(data) ? [...data] : { ...data })
    .then(response => response?.data)
}

const form = async (url, data) => {
  return await axiosApi
    .post(url, data, {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    })
    .then(response => response?.data)
}

As you can see, for post and get utility methods I use a request interceptor that sets the default values. Thus I use Content-Type: application/json for them.

However, for form I overrode the Content-Type header to be a form.

I read some other questions, including:

Axios not passing Content-Type header

Axios Header's Content-Type not set for safari

But my server allows Content-Type to be sent in CORS requests:

Access-Control-Allow-Headers: authorization,content-type,x-client
Access-Control-Allow-Methods: POST
Access-Control-Allow-Origin: *

But when I use form method, I see that the Content-Type is not set to application/json, not application/x-www-form-urlencoded.

What have I done wrong?

Upvotes: 8

Views: 14779

Answers (1)

Phil
Phil

Reputation: 164736

By default Axios has excellent request body handling.

  • If it sees a plain JavaScript object or array, it uses application/json.
  • If you pass in a plain string or an instance of URLSearchParams, it uses application/x-www-form-urlencoded.
  • Pass in a FormData instance and it will use multipart/form-data

So why are there endless questions on Stack Overflow with customised content-type headers? I'd even go so far as to argue that unless your APIs are using proper content negotiation, you don't need to mess with the Accept header either.

I see no need for an interceptor in your case. Simply set the request header defaults on your instance

axiosApi.defaults.headers.common["X-Client"] = "React";
// and if your API actually uses content negotiation...
// axiosApi.defaults.headers.common.Accept = "application/json";

As for your url-encoded request, Axios 0.x supports this via URLSearchParams or a plain string. It will not automatically convert a plain object into application/x-www-form-urlencoded.

If your data is a flat object, you can use the following

const form = async (url, data) => {
  const encodedData = new URLSearchParams(data);
  return (await axiosApi.post(url, encodedData)).data;
};

If it's more complex, I would recommend using a library like qs.

Otherwise, wait for Axios 1.0 where you can apparently use this

axios.post(url, data, {
  headers: { "content-type": "application/x-www-form-urlencoded" }
});

Upvotes: 8

Related Questions