Good old xmlHttpRequest for scripting http requests

These days there are a ton of options for scripting http, I have written posts on axios, and fetch, but I still find myself using XMLHttprequest for these tasks. It does have it’s draw backs, compared to more modern solutions, but it is not that hard to quickly make a solution that makes use of more modern javaScript features like promises.

Using an XMLHTTPRequest pollyfill

There was once a time where the use of a pollyfill for XMLHttpRequest was a must, today more often then not it might not be as big of a deal. Of course it really comes down to browser share of your site, for me it does not seem to matter everyone is using late versions of IE, when they are using IE, which is not often.

Still If it is desired to push backward compatibility as far back as possible a pollyfill like this might be used.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var xhr;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
try {
xhr = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
console.log('error, no XHR support at all');
return;
}
}
}

This is only really needed if for some reason you want to march backward comparability of your project all the way back to IE 5. Maybe if for some reason you get a lot of traffic from china, or some country where there are still a lot of people using these browsers a Polly fill will be of interest.

However if you site analytics show nothing but IE 7, and older chances are there is not much of a reason to bother with the polly fill anymore, and you can just assume that it is there in window to work with.

In which case you can just use the constructor.

1
var xhr = new XMLHttpRequest();

Using XMLHttprequest to make a method for scripting http

I often prefer to make some kind of easy to use method that can be used with just one or two arguments, but can also be given additional things to work with via an options object, just like that of the popular solutions like axios.

So I might end up with something like this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
var http = function (argu, done, fail) {
var xhr = new XMLHttpRequest();
// if first argument is a string, assume it is a url for a get request
if (typeof argu === 'string') {
argu = {
url: argu
}
}
// use given argu object or default to an empty object
argu = argu || {};
// default method is GET, payload is null, and URL is location.href
argu.method = argu.method || 'GET';
argu.playload = argu.payload === undefined ? null : argu.payload;
argu.url = argu.url || location.href;
// default done and fail callbacks
argu.done = done || argu.done || function (res) { console.log(res);};
argu.fail = fail || argu.fail || function () {};
// given, or default beforeSend method
argu.beforeSend = argu.beforeSend || function (xhr, next) {
// if POST request, assume JSON
if (argu.method.toUpperCase() === 'POST') {
xhr.setRequestHeader('Content-type', 'application/json');
// custom send that uses JSON
argu.send = function (xhr,argu) {
xhr.send(JSON.stringify(argu.payload));
};
}
next();
};
// given or default send method
argu.send = argu.send || function (xhr,argu) {
// just send
xhr.send(argu.payload);
};
// open the request
xhr.open(argu.method, argu.url, true);
// setup on ready state method to call done or fail methods
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200) {
argu.done.call(this, this.response);
} else {
argu.fail.call(this);
}
}
};
// call before send, and send request
argu.beforeSend(xhr, function () {
argu.send(xhr,argu);
});
};

So then I can use it by just giving a single string, and a callback in a very tired yet true fashion like this:

1
2
3
4
5
6
// the method in action
http('https://openlibrary.org/api/books?bibkeys=ISBN:9780743487733;format=json', function() {
console.log(this.response);
});

Or the same request can be made by giving an object like this.

1
2
3
4
5
6
7
8
http({
url: 'https://openlibrary.org/api/books?bibkeys=ISBN:9780743487733;format=json',
done : function(){
console.log(this.response);
}
});

If I want to do something advanced with post requests or something involving custom headers, I can always give a custom beforeSend, and if necessary send method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
http(
// argu object with custom beforeSend
{
url: '/body',
method: 'POST',
payload: 'foo',
beforeSend: function (xhr, next) {
xhr.setRequestHeader('Content-type', 'text/plain');
next();
},
send: function (xhr, argu) {
console.log('okay sending now.');
xhr.send(argu.payload);
}
},
// done call back
function (res) {
console.log(res);
//g('app_out').value += '**********\n'
//g('app_out').value += res + '\n\n';
}
);

This should be the goal when making any kind of project like this. If I am making a simple get request I should only have to give a url, and a callback. However if I do need to do something more advanced with custom content types, and payloads I can do that without hacking over the source code.

Using a fetch pollyfill

Of course you could do what I just did, and throw together your own solution, but it might be best to just use something that is out there all ready, and see that it confroms to some kind of newer standard for this sort of thing. Because fetch is poised to be the new replacement for XMLHttprequest it might be a good idea to make (or find) some kind of pollyfill that does a good job of bringing fetch to older browsers. for that you might want to check out fetch.js.

Conclusion

XMLhttprequest is the best solution for scripting http if you care about trying to get your code to work on a wide range of browsers, as it is the tired yet way of doing it. For the most part I would not loose sleep over it thought if you choose to go with something more modern.