Is XMLHttpRequest() considered the "Angular" way?

3,412 views
Skip to first unread message

Michael Caputo

unread,
Dec 9, 2013, 11:18:25 AM12/9/13
to ang...@googlegroups.com
Ive been struggling with Angular $http.POST methods for a while now. I've proven that it can be done with the API that im hooking into by testing using straight up jQuery $.post requests with NO issue at all.

However, I realize that this is not the "angular" way.

I finally settled on using XMLHttpRequest() for my POST, and it works exactly how I want, however, i'm not really clear if this is considered the "acceptable" best practise Angular way of doing things.

Can anyone comment on using this method? Maybe provide me with guidance - i've really been at a loss with this for quite some time, and there seems to be a lot of misinformation with this particular feature of Angular (everything else has been a delight to work with).

Here is my code that seems to be working perfectly.


var xhr = new XMLHttpRequest();
xhr.open('POST', REQUEST_URL, true);
xhr.onreadystatechange = function (aEvt) {
if (xhr.readyState == 4) {
if(xhr.status == 200) {
var res = eval("(" + xhr.response + ")");
console.log(res);
if (res.response.success === true) {
notify('You\'ve successfully logged in! Now directing you to the home page.');
// setting logged in cookies
loginCookie.saveToken(res);
loginCookie.saveId(res);
loginCookie.savePower(res);
setTimeout(
function(){
// forwarding you to the home page
window.location.replace( BASE_PATH + '#/mystream' );
}, 1000
);
} else {
// error message
notify(res.response.messages[0]);
}
}else{
console.log("Error loading page\n");
console.log(res);
}
}
};
var fd = new FormData();
for (var i in $scope.session){
console.log('Adding');
fd.append(i,$scope.session[i]);
}
xhr.send(fd);


Thanks!

Sander Elias

unread,
Dec 9, 2013, 11:54:06 AM12/9/13
to ang...@googlegroups.com
Hi Michael,

What issues do you have with $http.post? At first glance I don't see anything special in your xhrRequest that should be very problematic in $http.post(). 
Are you sure you need an eval in your handler? This looks very vulnerable to a man in the middle attack to me!
Is this part of an logon page? 

Regards
Sander Elias 

Michael Caputo

unread,
Dec 9, 2013, 11:57:41 AM12/9/13
to ang...@googlegroups.com
I don't know the best way to describe what I need to do, I need to be able to set the request payload to look like this (in chrome). I haven't been able to successfully get it to work this way using the $http.post method.
Screen Shot 2013-12-09 at 11.55.52 AM.png

Sander Elias

unread,
Dec 9, 2013, 12:07:23 PM12/9/13
to ang...@googlegroups.com
Michael,

That's only the payload part of the request. I need a bit more than that!
It looks a bit like it's mime encoded.  What server-side software are you using?

Regards
Sander

Michael Caputo

unread,
Dec 9, 2013, 12:10:10 PM12/9/13
to ang...@googlegroups.com
It's a custom homebrew built api that I don't have any control over unfortunately.

Angular doesn't seem to send the proper data to it.

I was previously using this method:

return $http({
method: 'POST',
url: REQUEST_URL + '/Auth/StartSession',
params: data
}).
then(function(result) {
return result;
});

However, obviously using params (sending data through the URL), this is because I haven't been able to send data through the request payload as I have with the xhrRequest.

Daniel Tabuenca

unread,
Dec 9, 2013, 2:31:18 PM12/9/13
to ang...@googlegroups.com

Use the data: instead of params: to pass the object you would like to go in the body of the request. I also don’t see that you are doing anything that can’t be done with basic $http service.

Michael Caputo

unread,
Dec 9, 2013, 2:35:54 PM12/9/13
to ang...@googlegroups.com
This is what I'm getting when using Data instead of Params.
 
[Error] Failed to load resource: Request header field Content-Type is not allowed by Access-Control-Allow-Headers. (StartSession, line 0)
[Error] XMLHttpRequest cannot load URL/Auth/StartSession. Request header field Content-Type is not allowed by Access-Control-Allow-Headers. (localhost, line 0)

Daniel Tabuenca

unread,
Dec 9, 2013, 4:55:54 PM12/9/13
to ang...@googlegroups.com

Is this a cross-domain request? Access-Control-Allow-Headers are related to CORS which usually means you are involved in a cross-domain request.

Angular defaults to posting as JSON rather than application/x-www-form-urlencoded, this means if doing a cross-domain request the borwser will issue an OPTIONS pre-flight request and Content-Type header must be specifically allowed by the server.

To solve your issue you can try the following:

Daniel Tabuenca

unread,
Dec 9, 2013, 4:56:37 PM12/9/13
to ang...@googlegroups.com
Message has been deleted

Michael Caputo

unread,
Dec 9, 2013, 5:15:48 PM12/9/13
to ang...@googlegroups.com
I have the ability to test using the same domain as the api. I just did a test with this configuration, and this is what my request payload looks like:
Screen Shot 2013-12-09 at 5.13.49 PM.png

Daniel Tabuenca

unread,
Dec 9, 2013, 5:20:54 PM12/9/13
to ang...@googlegroups.com
Could you post the full request header text (not a screenshot click on 'view source' and copy and paste the text) of the request headers?

Could you also copy and paste the URL from the browser location bar?

Michael Caputo

unread,
Dec 10, 2013, 9:10:00 AM12/10/13
to ang...@googlegroups.com
Thank you for your help Daniel and Sander.

Here is all of the Headers (omitting the DOMAIN, replaced with "DOMAIN")

  1. Request URL:
  2. Request Method:
    POST
  3. Status Code:
    200 Okay
  4. Request Headersview parsed
    1. POST /Auth/StartSession HTTP/1.1 Host: DOMAIN.local Connection: keep-alive Content-Length: 95 Cache-Control: no-cache Pragma: no-cache Accept: application/json, text/plain, */* Origin: http://DOMAIN.local User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1733.0 Safari/537.36 Content-Type: application/json;charset=UTF-8 DNT: 1 Referer: http://DOMAIN.local/web/ Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 Cookie: _ga=GA1.2.1713251720.1380311013
  5. Request Payloadview parsed
    1. {"email":"mi...@flashpunk.ca","first_name":"Michael","last_name":"Caputo","password":"asdfasdf"}
  6. Response Headersview parsed
    1. HTTP/1.0 200 Okay Date: Tue, 10 Dec 2013 14:06:35 GMT Server: Apache/2.2.22 (Ubuntu) X-Powered-By: PHP/5.3.10-1ubuntu3.7 Content-Length: 598 Access-Control-Allow-Origin: * Connection: close Content-Type: application/json

The URL in the location bar (omitting the domain):

Sander Elias

unread,
Dec 10, 2013, 9:41:31 AM12/10/13
to ang...@googlegroups.com
Hi Micheal,

this is the $http version? can you do the same for the xhr version?

Regards
Sander
Message has been deleted

Michael Caputo

unread,
Dec 10, 2013, 9:52:04 AM12/10/13
to ang...@googlegroups.com
Yes, the previous was the $http version, this is the xhr version:


  1. Request Method:
    POST
  2. Status Code:
    200 Okay
  3. Request Headersview parsed
    1. POST /Auth/StartSession/ HTTP/1.1 Host: DOMAIN.local Connection: keep-alive Content-Length: 462 Cache-Control: no-cache Pragma: no-cache Origin: http://DOMAIN.local User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1734.0 Safari/537.36 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryUJ7XbsCjXxGHZ7l5 Accept: */* DNT: 1 Referer: http://DOMAIN.local/web/ Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 Cookie: _ga=GA1.2.1713251720.1380311013
  1. Request Payload
    1. ------WebKitFormBoundaryUJ7XbsCjXxGHZ7l5 Content-Disposition: form-data; name="email" mi...@flashpunk.ca ------WebKitFormBoundaryUJ7XbsCjXxGHZ7l5 Content-Disposition: form-data; name="first_name" Michael ------WebKitFormBoundaryUJ7XbsCjXxGHZ7l5 Content-Disposition: form-data; name="last_name" Caputo ------WebKitFormBoundaryUJ7XbsCjXxGHZ7l5 Content-Disposition: form-data; name="password" asdfasdf ------WebKitFormBoundaryUJ7XbsCjXxGHZ7l5--
  2. Response Headersview parsed
    1. HTTP/1.0 200 Okay Date: Tue, 10 Dec 2013 14:50:14 GMT Server: Apache/2.2.22 (Ubuntu) X-Powered-By: PHP/5.3.10-1ubuntu3.7 Content-Length: 1007 Access-Control-Allow-Origin: * Connection: close Content-Type: application/json

Sander Elias

unread,
Dec 10, 2013, 10:20:03 AM12/10/13
to ang...@googlegroups.com
Hi Micheal,

Ok, you need to transform your form data, something like this will probably work:
    function toFormData(data) {
        var fd = new FormData();
        for (var i in data){
            console.log('Adding');
            fd.append(i,data[i]);
        }
        return fd;
    }

    $http({
        method: 'POST',
        URL: '/Auth/StartSession/',
        headers: {
            'Content-Type': 'multipart/form-data'
        },
        data : $scope.session,
        transformRequest : toFormData
    });

Regards
Sander Elias

Sander Elias

unread,
Dec 10, 2013, 10:37:37 AM12/10/13
to ang...@googlegroups.com
Oh, an small update,


if the above doesn't work, try,
    headers: { 'Content-Type': false },
in stead of,
    headers: {Content-Type: 'multipart/form-data'},

that will cause the underlying xhr request to put in the type; boundary stuff you need!

Regards
Sander


Michael Caputo

unread,
Dec 10, 2013, 11:19:58 AM12/10/13
to ang...@googlegroups.com
Once again, thank you for your time Sander, I really appreciate it.

I've added your code in, and it seems like it's really close, but for some reason our API is returning an error. The error isn't very descriptive at the moment, and our back end dev isn't around to give me more details unfortunately. This is the headers i'm getting (multipart vs false content type gives a very similar response):

Request Method:POST
Status Code:200 Okay
Request Headersview parsed
POST /Auth/StartSession HTTP/1.1
Host: DOMAIN.local
Connection: keep-alive
Content-Length: 462
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Content-Type: false
DNT: 1
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Request Payload
------WebKitFormBoundary6uiP3pKhBAATTHJ0
Content-Disposition: form-data; name="email"

------WebKitFormBoundary6uiP3pKhBAATTHJ0
Content-Disposition: form-data; name="first_name"

Michael
------WebKitFormBoundary6uiP3pKhBAATTHJ0
Content-Disposition: form-data; name="last_name"

Caputo
------WebKitFormBoundary6uiP3pKhBAATTHJ0
Content-Disposition: form-data; name="password"

asdfasdf
------WebKitFormBoundary6uiP3pKhBAATTHJ0--
Response Headersview parsed
HTTP/1.0 200 Okay
Date: Tue, 10 Dec 2013 16:15:18 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.3.10-1ubuntu3.7
Content-Length: 598
Message has been deleted

Michael Caputo

unread,
Dec 10, 2013, 11:39:05 AM12/10/13
to ang...@googlegroups.com
False was NOT between quotes.

{ 'Content-Type': false }

and i tried:

{'Content-Type': 'multipart/form-data'}

as well.

Sander Elias

unread,
Dec 10, 2013, 11:40:05 AM12/10/13
to ang...@googlegroups.com
Ok, perhaps you can try undefined  instead of false! 

Michael Caputo

unread,
Dec 10, 2013, 11:42:04 AM12/10/13
to ang...@googlegroups.com
Interesting, that seems to have worked!
Reply all
Reply to author
Forward
0 new messages