简体   繁体   中英

How do I manually cancel a XMLHttpRequest file upload (stream) on the server

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.

Under 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.net/?p=393

By the way, you run into the same problems if you're checking the file header for the content-type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM