如何在服务器上手动取消XMLHttpRequest文件上载(流)

时间:2013-11-14 10:35:19

标签: javascript node.js express stream xmlhttprequest

我正在使用XMLHttpRequest(Level 2)将文件上传到node.js服务器。我正在检查文件流以获取服务器端的有效标头。现在,如果流式传输时出现任何错误,我想触发取消上传。我的XMLHttpRequest代码非常简单:

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);
});

在服务器端,我将req流通过我的验证器传送到文件流中。如果在验证时发生任何错误,我希望XMLHttpRequest中止上传。但只是发送400响应请求根本不起作用。我向xhr注册了各种各样的听众,但没有一个人开火。它似乎并不关心400,仍然试图上传文件。通常我会期望onreadystatechange事件会在这种情况下发生。

我尝试通过发出一个req.end()来关闭req,但这看起来有点苛刻并且揭示了另一个好奇心。如果我这样做,XMLHttpRequest将重试7次(在Chrome中;在Firefox中5次;在任何地方记录?)。

编辑:保罗建议:

  

...连接在从服务器接收任何状态之前关闭...

在服务器端,我尝试听取响应的结束事件。

  checkedFile.on('error', function (err) {
    res.status(400);
    res.end();
  });

  res.on('finish', function () {
    req.destroy();
  });

但无论如何它都会重试。我只是不关心400。

也许还有另一种取消方式而不会破坏请求流?

第二次编辑:可以在不破坏请求流的情况下结束请求:

checkedFile.on('wrong', function (err) {
  checkedFile.end();
  res.writeHead(400,  { 'Connection': 'close' });
  res.end();
});

但XHR仍在重试请求。

2 个答案:

答案 0 :(得分:3)

在某些情况下,如果服务器提前关闭连接,则允许客户端重试请求,这正是Chrome在您的示例中所做的事情。此行为在HTTP 1.1 specification, 8.2.4

中定义
  

如果HTTP / 1.1客户端发送包含请求正文的请求,但不包含具有“100-continue”期望的Expect请求标头字段,并且客户端未直接连接到HTTP / 1.1源服务器,如果客户端在从服务器接收任何状态之前看到连接关闭,客户端应该重试该请求。

如果您想取消XMLHttpRequest,您应该听取XHR的error事件,然后调用abort() method,这会阻止Chrome重新发送请求。

答案 1 :(得分:1)

好吧,似乎必须忍受这个:

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

顺便说一句,如果您正在检查内容类型的文件头,则会遇到同样的问题。