Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Content-Type application/x-www-form-urlencoded #362

Closed
alborozd opened this issue Jun 28, 2016 · 220 comments
Closed

Content-Type application/x-www-form-urlencoded #362

alborozd opened this issue Jun 28, 2016 · 220 comments

Comments

@alborozd
Copy link

alborozd commented Jun 28, 2016

Try to send request with content type application/x-www-form-urlencoded

var data = Querystring.stringify({ 
                "grant_type": "password",
                "username": login,
                "password": password
            });
axios.post(Urls.login, data);

but there is no such header in request.

I tried to use code:

  var data = Querystring.stringify({ 
                "grant_type": "password",
                "username": login,
                "password": password
            });
        return axios({
            method: 'post',
            url: Urls.login,
            data: data,
            headers: {
                'Content-type': 'application/x-www-form-urlencoded'
            }
        });

same problem

jquery code works fine:

$.ajax({
            url: Urls.login,
            data: data,
            type: "POST",
            headers: {
                'Content-type': 'application/x-www-form-urlencoded'
            }
        });

How can I use axios to send request with this header?

@mzabriskie
Copy link
Member

mzabriskie commented Jun 28, 2016

That should work as you've shown. Sounds like a bug. I will look into it.

@alborozd
Copy link
Author

alborozd commented Jun 29, 2016

The cause is interceptors. I can't send request with that Content-Type only when I use interceptors.

Here is my code:

axios.interceptors.request.use(function (config) {
        var token = LoginStore.getJwt();
        if (token) {
            config.headers["Authorization"] = "Bearer " + token;
        }

            return config;
        }, function (error) {    
            return Promise.reject(error);
        });

Inside interceptor I can see 'Content-Type' header, but it is not sent to the server.
Do I correctly use interceptors?

@rahuljiresal
Copy link

Any updates on this? I have the same issue. Axios doesn't send the header I set.

@rahuljiresal
Copy link

rahuljiresal commented Jun 30, 2016

This seems to be the culprit line → https://github.com/mzabriskie/axios/blob/master/lib/adapters/xhr.js#L117

Any idea why the Content-Type header is removed before the request is sent?

A workaround option is to change your data to data || {} when you're making an axios request. This will make sure data is not undefined.

@mzabriskie
Copy link
Member

mzabriskie commented Jun 30, 2016

It looks like the logic for removing Content-Type when requestData is undefined came in this commit 9096d34. There is no indication why it was added however.

I would vote if the requestData is undefined and method is PUT, POST or PATCH and no Content-Type has been set, then default Content-Type to application/x-www-form-urlencoded. Otherwise just honor whatever has been specified.

@nickuraltsev
Copy link
Member

@mzabriskie But in the code snippet provided by @alborozd, the data is set to Querystring.stringify({...}), so requestData should not be undefined, right?

@alborozd
Copy link
Author

alborozd commented Jul 1, 2016

@mzabriskie I think you're right. When I use request interceptor fiddler shows that data is empty. Without interceptor I can see data and header and it works fine.

So, probably the problem occurs when you work with interceptors.

@damianprzygodzki
Copy link

damianprzygodzki commented Jul 16, 2016

No interceptor is needed to crash this thing. I've set content type header defaults axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';, and i can't send any payload in POST body.

I've used workaround with URLSearchParams:

    var params = new URLSearchParams();
    params.append('email', email);
    return (dispatch) => {
        axios.post('/stack/' + uri, params)

But this is not supported by Safari and IE.

Edit: Okay :) Next update on workaround. Full supported workaround is send data as query string.
data: "flashcard=" + JSON.stringify(flashcard) + "&stackUri=" + stackUri. It hurts, but it works 👍

@nickuraltsev
Copy link
Member

You can use a library like qs instead:

var qs = require('qs');
axios.post('/foo', qs.stringify({ 'bar': 123 });

@alborozd
Copy link
Author

this is not a solution. What is difference if I will use "Querystring" or "qs" ? The problem is the header ['Content-Type'] = 'application/x-www-form-urlencoded' is empty because of interceptors.

@damianprzygodzki
Copy link

damianprzygodzki commented Dec 8, 2016

Any updates here? Because i've lost 1h today on researching why my POSTs are not affecting API (til i reminded about that issue)... Or there are no plans to fix that and it's better to go somewhere else?

@Dunkat
Copy link

Dunkat commented Dec 8, 2016

I have the same problem... still waiting for fix...

@cadavre
Copy link

cadavre commented Dec 8, 2016

Please reopen @nickuraltsev as this is not fixed by your solution.

+1 for issue.

@hyanmandian
Copy link

I use a interceptor with qs library to solve this problem. Works fine for me.

import qs from 'qs';

axios.interceptors.request.use((request) => {
  if (request.data && request.headers['Content-Type'] === 'application/x-www-form-urlencoded') {
      request.data = qs.stringify(request.data);
  }
  return request;
});

@brickgale
Copy link

+1 for issue.

@nickuraltsev nickuraltsev reopened this Dec 9, 2016
@damianprzygodzki
Copy link

hyanmandian commented 14 hours ago
I use a interceptor with qs library to solve this problem. Works fine for me.

Great, but it is not a way to solve issue in libraries IMHO by installing another.

@reznord
Copy link

reznord commented Dec 21, 2016

You can just add a data: {} to the config, so the interceptor doesn't skip the headers which we specify.

This is what I did, and it worked for me:

import request from 'axios'

export const playSound = (soundFile) => (dispatch) => {
	dispatch(playSoundPending());
	return request
    .get(`/play/audio/${soundFile}`, { headers: {'Content-Type': 'audio/x-wav'}, data: {} })
    .then(response => response.data)
    });
};

This changed the Content-Type from application/json to audio/x-wav for me in the request headers in the network tab.

@sandervspl
Copy link

Has this been fixed yet? I can't seem to set my Content-Type with any of the solutions posted here.

@szare
Copy link

szare commented Jan 25, 2017

I have same problem, any help?

@szare
Copy link

szare commented Jan 25, 2017

I solved the problem using encodeURIComponent:

static getToken(username, password) {
return axios({
method: 'post',
url: 'endpoints',
data: Username=${**encodeURIComponent**(username)}& password=${**encodeURIComponent**(password)}& Grant_type=password
})

@joshlangner
Copy link

bump. One would definitely assume that if one sets defaults, they would be always be respected. Axios is definitely ignoring the defaults in certain contexts, causing issues for poor folks.

@joshlangner
Copy link

Here's a more specific merge where this happened: https://github.com/mzabriskie/axios/pull/195/files

@polyakoff
Copy link

+1 for this issue.
Spent over 3 hours trying to figure out what's wrong with my Tomcat config and apparently appears my headers were stolen on the way to the server. Workarounds did not help. God save the headers!

@usopan
Copy link

usopan commented Mar 16, 2017

@polyakoff how did you solve for this?or are you still stuck. What I have observed is that this issue happens intermittently

@polyakoff
Copy link

@usopan Still stuck.

@usopan
Copy link

usopan commented Mar 16, 2017

I moved to isomorphic-fetch for this particular request as a workaround.
Things seem to work OK on most browsers, but still not working on certain Safari versions.
I am begining to think that Safari is screwing me.

@Felomeng
Copy link

Felomeng commented Jan 6, 2019

Got the same issue. And if I set the key to anything else, it works, except for "Content-Type"! Please help!

@perry-mitchell
Copy link

I've actually had to create yet another messy hybrid app by using fetch in browsers and axios in node and within react-native. Seems funny that it's like this and not the other way around. Really hoping to see this tackled soon so I can remove my monkey-patch.

I think it's important to realise that this is definitely not only an issue with querystring.. My body content is just raw text with no parameters, yet I can't send it using axios with a Content-Type.

@Felomeng
Copy link

I tried using post, it works fine, default of post is json

@StriderHND
Copy link

I'm experiencing this bug right now... so there Is no solution for this after years? wow...

@laurenz-glueck
Copy link

I created a PR that would fix the problem over two months ago... I don’t understand why it not get merged?!

@jovanmaric
Copy link

I created a PR that would fix the problem over two months ago... I don’t understand why it not get merged?!

Keep in mind that no one has pushed anything since september last year, maybe they're searching for maintainers?. Also, I think you missed a test when I compare your PR with: https://github.com/axios/axios/pull/1544/files

@mzabriskie could you maybe take the responsibility to merge one of these PR's? As currently some software requires get requests to have a content-type set (RoR params for instance: https://guides.rubyonrails.org/api_app.html#using-actiondispatch-request). The solution specified in #362 (comment) seems like the proper way to go and it would most of all solve all the desperate hacks like using fetch for this specific use case.

@rodrigogs
Copy link

I moved to got pagkage, since axios seems abandoned.

@bertolo1988
Copy link

bertolo1988 commented Feb 19, 2019

So Axios is officially unable to send requests with 'Content-Type': 'application/x-www-form-urlencoded' or does @ChBernat solution actually work?

@funkindy
Copy link

Is there any workaround on this issue atm?

@ghost
Copy link

ghost commented Feb 25, 2019

Is there any workaround on this issue atm?

Lookup a year up here and you will see plenty of workarounds... Though I would recommend, like others and myself included, move on from axios. It's abandoned...

@justintime4tea
Copy link

Wow... they should just abandon the project at this point, I know I am. Almost 3 years since issue originally reported and now we're still trying to solve this thing? Unbelievable. I love open source so I'm not harboring any ill feelings for this project not have maintainers but... it's used by TONS of people so the least you could do is abandon it so we all know this project is dead/dying. Thanks.

@kslr
Copy link

kslr commented Mar 19, 2019

@justintime4tea Do you have a new recommendation?

got

@justintime4tea
Copy link

@kslr got or request seems like what everyone else has started migrating too. I'm trying to stick with Axios but I think it'll end up just coming down to me writing some abstraction layer over it so I can swap out the underlying HTTP request library and then if I use a different library which has a "built-in" HTTP client it uses, just let it do its thing.

@RocaManuel
Copy link

I tried something like this and worked for me.
Maybe not the best solution but it can really help (i think), any suggestion, if this solution is horrible, is welcome.

const foo= yield qs.stringify({ 'grant_type' : 'yourGrantType', 'param' : param, 'param' : param }) const bar= yield axios.post('/baz', foo)

I have removed the header, and it seems like it has received well.

@javaLuo
Copy link

javaLuo commented Apr 16, 2019

axios({
  url,
  method: 'POST',
  headers:{
    'Content-Type': 'application/json'
  },
  data: null, // important
})

@leonardocouy
Copy link

I had two problems using RoR as backend.

My context:

I had a project using deprecated vue-resource and everything works ok without additional config. And now, I'm organizing the project's dependencies and replacing deprecated dependencies, so I replaced vue-resource with axios ;)...


But, we had some problems and below I will share what I do to solve these problems. Maybe help someone! So sorry if I haven't helped you as you expected

First problem, the problem is the same as this issue, I solved using:

axios.interceptors.request.use(config => {
  config.paramsSerializer = params => qs.stringify(params);
  return config;
});

Now, params like:

q: {
  search: "Something",
  sort: "asc",
}

will be transformed to:
http://xxxx/?q%5Bsearch%5D=something&q%5Bsort%5D=asc

this parsed will be:

q[search]: something
q[sort]: asc

Second problem, RoR is returning HTML response instead of JSON response:

This problem occurs because our backend must distinguish AJAX requests from other types of requests.

By default, vue-resource already set X-Requested-With header as expected. But, axios not. So, I had to define this key in the request header. My Axios global config was as follows in the end:

axios.interceptors.request.use(config => {
  config.paramsSerializer = params => qs.stringify(params);
  return config;
});
axios.defaults.headers.common['Accept'] = 'application/json';
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

===

If you use Rails as backend and no one of the solutions worked for you, let me know, maybe I help you =).

@carlosen14
Copy link

use this.. https://gist.github.com/akexorcist/ea93ee47d39cf94e77802bc39c46589b#gistcomment-2878451

@manishn2184
Copy link

Am working on react-native and getting bad request 400 error when use this :
import * as qs from 'querystring';
axios.post(url,qs.stringify({
'first_name': 'deep',
'last_name': 'palotra',
}),{
headers : {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
}).then((response)=>{
console.log('worked')
}).catch((error)=>{
console.log('error')
console.log(error)
})

@javaxiaoyetan
Copy link

so,how to resolve this problem?

@e3bmo3ty
Copy link

any solution :(

@e3bmo3ty
Copy link

Solved By qs

{ data: qs.stringify(bodyObject) }

@chinesedfan
Copy link
Collaborator

Sad to see that so many people are confused in this issue. I have try my best to read those comments. But it seems to have involved many other problems.

Everyone, forgive me to close it. If someone can open a new issue to describe the problem clearly, that will be really big thanks to you.

@tapaz1
Copy link

tapaz1 commented Feb 17, 2020

Hey everyone,

I thought I'd chime in as I wasted almost a full working day of my life trying to solve this. This may help some partially, or completely so here's to hoping this is useful.

My reply stems from seeing various reasons why a POST was failing with Axios ranging from:

  1. 400 Bad Request
  2. Can't post with custom Headers (like this thread)
  3. Need to serialize/stringify the data/payload

I was facing the same issue as everyone in this thread with the Bad Request 400 when passing in custom headers to Axios in the config like this, and tried many of the responses here, like using qs.stringify(), setting data in the config to null or {} to no avail.

  1. Note - Adding the .catch() block and logging the error like so really helped me because I was able to surface an error that wasn't so cryptic. I was able to use the message to debug and ultimately figure out the issue I was having.

  2. It's important in the .then() block to return response.data, otherwise you'll run into this error:

Converting circular structure to JSON

Now my issue was the api POST body was not what the endpoint wanted, but I couldn't see it until I was able to log the error.

Further, I'm also using NestJS and the HttpService, which is a wrapper around Axios, and that further complicated the issue because the real error wasn't bubbling up in the catchError callback in my pipe.

So here is the solution for both pure Axios and NestJS.

Axios:

const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
return axios.post('https://some-made-up-endpoint, dataString, { headers })
.then(resp => resp.data)
.catch(error => {
this.logger.log('ERROR: ${JSON.stringify(error.response.data)}');
});

NestJS:

const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
return this.http.post('https://some-made-up-endpoint, dataString, { headers }).pipe(
map(response => response.data), // This is important otherwise - circular JSON error
catchError((error: any) => {
this.logger.error('[[[[ ERROR TRYING TO FETCH TOKEN: ${error.message} ]]]]');
return of()
})
).toPromise();

TLDR;

  1. Add the .catch() block to properly log the real error, otherwise it's 400 Bad Request
  2. Make sure your data signature matches what the API is expecting. This is part of the reason an error exists since a code 400 is a 'Bad Request'
  3. Return the response.data in the .then() block if you're using Axios, or in a map operator if you're using NestJS or you'll get the Converting circular JSON error

Sorry for the long post and good luck everyone!

Cheers

@powehuda
Copy link

powehuda commented Mar 1, 2020

Am working on react-native and getting bad request 400 error when use this :
import * as qs from 'querystring';
axios.post(url,qs.stringify({
'first_name': 'deep',
'last_name': 'palotra',
}),{
headers : {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
}).then((response)=>{
console.log('worked')
}).catch((error)=>{
console.log('error')
console.log(error)
})

this work for me. with query stringfy thanks a lot.
you save my live

@jerrychong25
Copy link

You can use a library like qs instead:

var qs = require('qs');
axios.post('/foo', qs.stringify({ 'bar': 123 });

Your solution is working. Thanks a lot!

@axios axios locked and limited conversation to collaborators May 21, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests