I am using XMLHttpRequest (Level 2) to upload a file to a node.js server. I am checking the file-stream for the valid header on the server side. Now I want to trigger a cancellation of the upload if there are any errors while streaming. My XMLHttpRequest code is very simple:
var xhr = new XMLHttpRequest();
var file;
$('#file').on('change', function(e) {
file = this.files[0];
file.filename = this.files[0].name;
});
$('#submit').on('click', function(e) {
e.preventDefault();
xhr.open('POST', '/upload', true);
xhr.send(file);
});
On the server side I am piping the req stream through my validator into a file stream. I want the XMLHttpRequest to abort the upload if any errors occur while validating. But just sending a 400 as response to the request doesn't work at all. I registered all kinds of listeners to the xhr but none of them fire. It doesn't seem to care about the 400 at all and still tries to upload the file. Normally I would expect that the onreadystatechange event would fire on this occasion.
I tried closing the req by issuing an req.end() but that seems a bit harsh and reveals another curiosity. If I do that, the XMLHttpRequest retries to send the POST request exactly 7 times (in Chrome; 5 times in Firefox; is this documented anywhere?).
Edit: As Paul suggested:
...connection close before receiving any status from the server...
On the server side I try to listen to the finish event of the response.
checkedFile.on('error', function (err) {
res.status(400);
res.end();
});
res.on('finish', function () {
req.destroy();
});
But it retries anyway. I just doesn't care about the 400.
Maybe there is another way of canceling without destroying the request stream?
Second edit: It is possible to end the request without destroying the request stream:
checkedFile.on('wrong', function (err) {
checkedFile.end();
res.writeHead(400, { 'Connection': 'close' });
res.end();
});
But the XHR is still retrying the request.
I am using XMLHttpRequest (Level 2) to upload a file to a node.js server. I am checking the file-stream for the valid header on the server side. Now I want to trigger a cancellation of the upload if there are any errors while streaming. My XMLHttpRequest code is very simple:
var xhr = new XMLHttpRequest();
var file;
$('#file').on('change', function(e) {
file = this.files[0];
file.filename = this.files[0].name;
});
$('#submit').on('click', function(e) {
e.preventDefault();
xhr.open('POST', '/upload', true);
xhr.send(file);
});
On the server side I am piping the req stream through my validator into a file stream. I want the XMLHttpRequest to abort the upload if any errors occur while validating. But just sending a 400 as response to the request doesn't work at all. I registered all kinds of listeners to the xhr but none of them fire. It doesn't seem to care about the 400 at all and still tries to upload the file. Normally I would expect that the onreadystatechange event would fire on this occasion.
I tried closing the req by issuing an req.end() but that seems a bit harsh and reveals another curiosity. If I do that, the XMLHttpRequest retries to send the POST request exactly 7 times (in Chrome; 5 times in Firefox; is this documented anywhere?).
Edit: As Paul suggested:
...connection close before receiving any status from the server...
On the server side I try to listen to the finish event of the response.
checkedFile.on('error', function (err) {
res.status(400);
res.end();
});
res.on('finish', function () {
req.destroy();
});
But it retries anyway. I just doesn't care about the 400.
Maybe there is another way of canceling without destroying the request stream?
Second edit: It is possible to end the request without destroying the request stream:
checkedFile.on('wrong', function (err) {
checkedFile.end();
res.writeHead(400, { 'Connection': 'close' });
res.end();
});
But the XHR is still retrying the request.
Share Improve this question edited Nov 14, 2013 at 14:55 chmanie asked Nov 14, 2013 at 10:35 chmaniechmanie 5,0863 gold badges22 silver badges28 bronze badges2 Answers
Reset to default 4Under some circumstances, if the server prematurely closes the connection, then the client is allowed to retry requests, which is what Chrome is doing in your example. This behavior is defined in the HTTP 1.1 specification, 8.2.4:
If an HTTP/1.1 client sends a request which includes a request body, but which does not include an Expect request-header field with the "100-continue" expectation, and if the client is not directly connected to an HTTP/1.1 origin server, and if the client sees the connection close before receiving any status from the server, the client SHOULD retry the request.
If you want to cancel the XMLHttpRequest, you should listen on the error
event of the XHR and then call its abort()
method, which will prevent Chrome from re-sending the request.
OK it seems, one has to live with this:
What happens when no response is received for a request? I'm seeing retries
Inconsistent browser retry behaviour for timed out POST requests
http://geek.starbean/?p=393
By the way, you run into the same problems if you're checking the file header for the content-type.