Recently I found very strange behavior of IE8/9 when sending XHR data. I'd like to ask you if you have ever seen such behavior? Is it IE bug? How can I protect my server from "empty" request generated by IE? Here are more details:
I found out that when your page tries to send XHR data and JavaScript freezes or lags browser, IE lags sending POST data to server. To make it clear, here are steps to reproduce:
Create simple server which dumps POSTs received. I've used Node.JS for tests. You can find corresponding codes at the bottom of the post.
Open localhost:8080 in IE, open debug window and start debuging scripts with breakpoint set in line 51 of file localhost:8080
Hit Send by JQuery
. You should have your javascript waiting on the breakpoint and server logged message:
--------------------------------------
14:04:19
REQUEST: /
HTTP HEADER:
accept = text/html, application/xhtml+xml, */*
accept-language = pl-PL
user-agent = Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
accept-encoding = gzip, deflate
host = localhost:8080
connection = Keep-Alive
--------------------------------------
14:04:35
REQUEST: /test
HTTP HEADER:
accept = */*
content-type = application/json
x-requested-with = XMLHttpRequest
referer = http://localhost:8080/
accept-language = pl
accept-encoding = gzip, deflate
user-agent = Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
host = localhost:8080
content-length = 24
connection = Keep-Alive
cache-control = no-cache
When you release JavaScript from the breakpoint server reports incoming data by new line:
POST: {"data1":10,"data2":123}
I've done the same test on Opera 12.15 and Chrome 27.0.1453.94 m and, as expected, POST data are sent immediately.
-- source codes --
Code for node.js server:
var http = require('http');
var qs = require('querystring');
var fs = require('fs');
http.createServer(function (req, res) {
console.log('--------------------------------------');
console.log(new Date().toLocaleTimeString());
console.log('REQUEST: ' + req.url);
console.log('HTTP HEADER: ');
for (var header in req.headers) {
console.log(' ' + header + ' = ' + req.headers[header]);
}
switch (req.method) {
case 'POST':
var body = '';
req.on('data', function (data) {
body += data;
});
req.on('end', function() {
console.log('POST: ' + body);
});
res.writeHead(200, {'Content-type': 'application/json'});
res.end(JSON.stringify({ succeeded: true, value: 'Hello world!' }));
break;
case 'GET':
fs.readFile('./servertest.html', function (err, data) {
if (err) {
throw err;
}
res.writeHeader(200, {'Content-type': 'text/html'});
res.end(data);
});
break;
}
}).listen(8080, 'localhost');
console.log('listening on localhost:8080');
Code for servertest.html:
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<button onclick="send()">Send by JQuery</button>
<button onclick="sendXHR()">Send by XHR</button>
</body>
<script type="text/javascript">
var _xhr;
function sendXHR() {
_xhr = new XMLHttpRequest();
new XHRStateChangeListener();
var url = '/testXHR';
var method = 'POST';
_xhr.open(method, url);
_xhr.setRequestHeader("Content-Type", "application/json");
_xhr.send(JSON.stringify({test: 'this is a test', aoawiejf:23423}));
}
function XHRStateChangeListener() {
callback = function() {
var msg;
if (_xhr.readyState == 4 && /200|304/.test(_xhr.status)) {
alert('ready: ' + _xhr.responseText);
}
};
_xhr.onreadystatechange = callback;
}
function send() {
$.ajax({
url: '/test',
type: 'POST',
data: JSON.stringify({data1: 10, data2: 123}),
contentType: 'application/json',
error: function(xhr, status, err) {
alert('Error: ' + err + '
Status: ' + status);
},
success: function (data) {
alert('succeeded! data: ' + data);
}
});
}
</script>
</html>
You are using sync-mode, right is async-mode:
replace _xhr.open(method, url);
by _xhr.open(method, url, true);//Async mode
Note: Remember "onreadystatechange" is only for async-mode
the problem may also be in this function (just a guess): JSON.stringify
try sending empty data, ie: data:""