myou11
myou11

Reputation: 27

Why does Axios send my POST request with Content-Type application/x-www-form-urlencoded when using a string as the request body?

I found this interesting behavior with axios while making POST requests. I am sending URLs that the user types in to my Spring RestController which accepts the request body as a String. It looks like this:

@PostMapping("user/{userId}/link")
public ResponseEntity<UserLinkDTO> addUserLink(
    @PathVariable(value = "userId") Integer userId, @RequestBody String url) {
    ...
}

On the front end, my axios request looks like this:

const saveUserLink = async (userId: number, url: string): Promise<UserLinkDTO> => {
  return axiosInstance.post(`user/${userId}/link`, url))
  .then(r => r.data)
);

When I send some arbitrary URLs (with = in them) like these:

https://www.google.com/search?client=firefox

https://www.yahoo.com/somePage?key=value&hello=world

the Spring POST method receives the url exactly as it was sent.

However, when I send some URLs like this (without any = in them):

https://www.google.com

https://www.yahoo.com/somePage

my Spring POST method receives the url with = appended to them! So the links are received as:

https://www.google.com=

https://www.yahoo.com/somePage=

I noticed the requests are being sent with Content-Type: application/x-www-form-urlencoded in my Network tab. However, based on axios docs, all requests should be serialized to JSON which would imply being sent with Content-Type: application/json. All the other requests I'm using are sent with Content-Type: application/json. It's only this one that gets converted to Content-Type: application/x-www-form-urlencoded.

I edited my axios post request to include some custom headers so I could change the Content-Type back to application/json:

const saveUserLink = async (userId: number, url: string): Promise<UserLinkDTO> => {
  return axiosInstance.post(`user/${userId}/link`, url, {
    headers: {
      'Content-Type': 'application/json',
    }
  })
  .then(r => r.data)
);

My Spring POST method is now able to receive the URLs above exactly as provided, regardless of if they have = in them or not. There is no longer an extra = appended to the links without any =.

Why is it that axios seems to change the Content-Type from application/json to application/x-www-form-urlencoded when providing a string as the request body?

Upvotes: 0

Views: 1572

Answers (1)

dunhuang
dunhuang

Reputation: 361

the default content-type in axios is 'application/x-www-form-urlencoded'

//https://github.com/axios/axios/blob/master/lib/defaults.js
var DEFAULT_CONTENT_TYPE = {
  'Content-Type': 'application/x-www-form-urlencoded'
};

//...

utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
});

while when request's data is an Object, axios sets contentType to 'application/json':

    if (utils.isObject(data)) {
      setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
      return JSON.stringify(data);
    }

Upvotes: 1

Related Questions