chm*_*nie 5 javascript xmlhttprequest stream node.js express
我正在使用 XMLHttpRequest(级别 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);
});
Run Code Online (Sandbox Code Playgroud)
在服务器端,我将 req 流通过验证器传输到文件流中。如果验证时发生任何错误,我希望 XMLHttpRequest 中止上传。但是仅仅发送 400 作为对请求的响应根本不起作用。我向 xhr 注册了各种监听器,但没有一个触发。它似乎根本不关心 400,仍然尝试上传文件。通常我预计 onreadystatechange 事件会在这种情况下触发。
我尝试通过发出 req.end() 来关闭 req,但这似乎有点苛刻并揭示了另一种好奇心。如果我这样做,XMLHttpRequest 会重试发送 POST 请求 7 次(在 Chrome 中;在 Firefox 中重试 5 次;这在任何地方都有记录吗?)。
编辑:正如保罗建议的那样:
...连接在从服务器接收任何状态之前关闭...
在服务器端,我尝试监听响应的完成事件。
checkedFile.on('error', function (err) {
res.status(400);
res.end();
});
res.on('finish', function () {
req.destroy();
});
Run Code Online (Sandbox Code Playgroud)
但无论如何它都会重试。我只是不在乎400。
也许还有另一种取消而不破坏请求流的方法?
第二次编辑:可以在不破坏请求流的情况下结束请求:
checkedFile.on('wrong', function (err) {
checkedFile.end();
res.writeHead(400, { 'Connection': 'close' });
res.end();
});
Run Code Online (Sandbox Code Playgroud)
但 XHR 仍在重试该请求。
在某些情况下,如果服务器过早关闭连接,则允许客户端重试请求,这就是 Chrome 在您的示例中所做的事情。此行为在HTTP 1.1 规范 8.2.4中定义:
如果 HTTP/1.1 客户端发送的请求包含请求正文,但不包含带有“100-Continue”期望的 Expect 请求标头字段,并且客户端未直接连接到 HTTP/1.1 源服务器,如果客户端在收到来自服务器的任何状态之前看到连接关闭,则客户端应该重试该请求。
如果你想取消XMLHttpRequest,你应该监听errorXHR的事件,然后调用它的abort()方法,这将阻止Chrome重新发送请求。