13

I am trying to make an XHR with JavaScript, but I can't get it to work correctly.

When I see the right requests in the "Network" tab of the Chrome developer tools I see that they have a "Form Data" section where are listed all the informations sent with the request, like this:

formdata

Now, I've tried making my XMLHttpRequest in any way I know, but I can't get that result.

I have tried this:

var xhr = new XMLHttpRequest(),
    form_data = "data%5Btumblelog%5D=drunknight&data%5Bsource%5D=FOLLOW_SOURCE_REBLOG";
    // this is uri encoded: %5b = [ and %5D = ]

xhr.open('POST','https://www.somesite.com/page?' + form_data, false);
xhr.send();

But I got this "Query String Parameters" instead of "Form Data":

querystringparameters

I have also tried this:

var xhr = new XMLHttpRequest(),
    formData = new FormData();

formData.append("data[tumblelog]", "drunknight");
formData.append("data[source]", "FOLLOW_SOURCE_REBLOG");
xhr.open('POST','https://www.somesite.com/page', false);
xhr.send(formData);

But I got this "Request Payload" instead of "Form Data":

payload

And, finally, I have tried this:

var xhr = new XMLHttpRequest(),
    formData = {
        "data[tumblelog]": "drunknight",
        "data[source]": "FOLLOW_SOURCE_REBLOG"
    };

xhr.open('POST','https://www.somesite.com/page', false);
xhr.send(JSON.stringify(formData));

But I got another "Request Payload" instead of "Form Data":

payload2


Now, my question is: how can I send my XMLHttpRequest in order to obtain the same result as shown in the FIRST image?

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
  • From what you've shown, I'm assuming that the first image is not of an _XMLHttpRequest_ but the request of a browser _Window_ ? This is a different mechanism to _XMLHttpRequest_ so naturally there will be differences. It seems to me like you're trying too hard to make the logged message match up rather than actually sending the data you want in the best way. – Paul S. Sep 06 '14 at 01:13
  • @PaulS. The problem is that I get a forbidden (403) error if I try to make my request. I just want to know what sort of method is used to send that kind of data. I can assure you that the first image is obtained using an XHR. – Marco Bonelli Sep 06 '14 at 01:16
  • The browser does a bunch of stuff for you when submitting a form. To reproduce the result, you have to do the same things in JS. Check out this article from MDN: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Using_nothing_but_XMLHttpRequest. Alternatively you could create/submit a form with JS to make your life easier. – pherris Sep 06 '14 at 01:36
  • `var form = document.createElement('FORM'); form.method='POST'; form.action='https://somesite.com/page'; var inputElem = document.createElement('INPUT'); inputElem.type = 'TEXT'; inputElem.name = 'data[tumblelog]'; inputElem.value = 'drunknight'; form.appendChild(inputElem); inputElem = document.createElement('INPUT'); inputElem.type = 'TEXT'; inputElem.name = 'data[source]'; inputElem.value = 'FOLLOW_SOURCE_REBLOG'; form.appendChild(inputElem); document.body.appendChild(form); form.submit();` – pherris Sep 06 '14 at 01:39
  • @pherris you probably should post that as an answer, perhaps using `xhr.send(form)` rather than `form.submit` – Paul S. Sep 06 '14 at 01:42

3 Answers3

18

You're missing the Content-Type header to specify that your data is form-like encoded.

This will work:

var xhr = new XMLHttpRequest(),
    data = "data%5Btumblelog%5D=drunknight&data%5Bsource%5D=FOLLOW_SOURCE_REBLOG";

xhr.open('POST','https://www.somesite.com/page', false);

// LINE ADDED
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

xhr.send(data);

EDIT

FormData is generally used to send binary data and will automatically set the Content-Type header to multipart/form-data (see FormData Spec and FormData Examples). However you have to make sure the server also accepts request using this MIME-type, which apparently is not your case, as you already tried and it didn't work.

  • 2
    This did not work for me because setting header "application/x-www-form-urlencoded" is wrong for FormData. See this ans https://stackoverflow.com/a/45194986/4502711 – Niraj Jul 18 '19 at 11:20
  • @Niraj this explains why when I tried the first method it didn't work for me and why I also wrote the second method. I'm gonna update my answer, thanks! – Matteo Bernardini Jul 18 '19 at 13:30
  • Confirmed that this doesn't work, @Niraj points out the reason. – Jorge.V Sep 02 '22 at 10:00
1

I noticed the OP tried using FormData in one of their iterations to solve the original problem.

I've recently started using the Fetch api for sending form data. It's designed with promises making it really easy to use (especially if there's a form to leverage for all of the inputs):

var form = document.forms[0];
var data = new FormData(form);
fetch(form.action, { method: form.method, body: data })
.then((response) => {
  // handle response
}).catch((error) => {
  // handle error
);

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

Darrin
  • 11
  • 1
-1

Posting this as an answer because I believe it will give you exactly what you want to know;

I just want to know what sort of method is used to send that kind of data. I can assure you that the first image is obtained using an XHR

You haven't given enough information for us to see how the "correct" version is generated, but you can capture the relevant bits you want, drop in code like this before the working XMLHttpRequest is .opened;

(function (obj, methods) {
    var i;
    function log() {
        console.log.apply(console, arguments);
    }
    for (i = 0; i < methods.length; ++i)
        obj[methods[i]] = (function (method_name, method) {
            return function () {
                log.call(null, method_name, arguments);
                return method.apply(this, arguments);
            }
        }(methods[i], obj[methods[i]]));
}(XMLHttpRequest.prototype, ['open', 'send', 'setRequestHeader']));

Now perform the action to make it fire and the relevant parameters will be logged so you can see exactly what happens to it as it is set up and sent, which should allow you to know what to pass into your one.


The problem is that I get a forbidden (403)

I'm going to assume this is not a same origin security-error because this looks server-returned and not a browser-initiated abort

Paul S.
  • 64,864
  • 9
  • 122
  • 138