【问题标题】:Multiple synchronous XmlHttpRequests getting rejected/aborted多个同步 XmlHttpRequests 被拒绝/中止
【发布时间】:2016-07-11 09:52:40
【问题描述】:

为了找点乐子并了解更多关于 JS 和新的 HTML5 规范的信息,我决定构建一个文件上传插件供我个人使用。

选择我的文件后,我将文件发送到我的 Web Worker 以拼接成 1mb 的块并单独上传到我的服务器。我选择单独发送它们以受益于单独的进度回调和暂停/恢复功能(稍后)。

我遇到的问题是当我选择了很多要上传的文件时。如果我只选择8,没有问题。如果我选择 99,服务器会在大约第 20 个文件之后拒绝/中止,尽管有时它可能会在 22、31、18 之后停止 - 完全随机。

Firefox 在中止之前可以摆脱比 Chrome 更多的麻烦。 Chrome 称它们为“失败”,而 Firefox 称它们为“中止”。 Firefox 通常会在大约文件 40 之后中止文件。不仅如此,我的测试服务器也变得无响应并抛出“连接已重置”错误 - 不到 20 秒后再次响应。

因为我使用的是 Web Worker,所以我将 XmlHttpRequests 设置为同步,以允许每个请求在开始新请求之前完成,并且 PHP 脚本位于同一域中,所以看到请求被拒绝,我感到很困惑并且很想听听我的代码有什么问题导致这种情况发生。

这是发送给 Worker 的插件部分。无关紧要,但谁知道呢:

var worker = new Worker('assets/js/uplift/workers/uplift-worker.js');
worker.onmessage = function(e) {
    console.log(e.data);
};
worker.postMessage({'files':filesArr});

这是 uplift-worker.js:

var files = [], p = true;

function upload(chunk) {
    var upliftRequest = new XMLHttpRequest();
    upliftRequest.onreadystatechange = function() {
        if (upliftRequest.readyState == 4 && upliftRequest.status == 200) {
            // do something
        }
    };
    upliftRequest.setRequestHeader("Cache-Control", "no-cache");
    upliftRequest.setRequestHeader("X-Requested-With", "XMLHttpRequest");
    upliftRequest.open('POST', '../php/uplift.php', false);
    upliftRequest.send(chunk);
}

function processFiles() {
    for (var j = 0; j < files.length; j++) {
        var blob = files[j];
        const BYTES_PER_CHUNK = 1024 * 1024; // 1mb chunk sizes.
        const SIZE = blob.size;
        var start = 0,
            end = BYTES_PER_CHUNK;
        while (start < SIZE) {
            var chunk = blob.slice(start, end);
            upload(chunk);
            start = end;
            end = start + BYTES_PER_CHUNK;
        }
        p = j == (files.length -1);
        self.postMessage(blob.name + " uploaded successfully");
    }
}

self.addEventListener('message', function(e) {
    var data__Files = e.data.files;
    for (var j = 0; j < data__Files.length; j++) {
        files.push(data__Files[j]);
    }
    if (p) processFiles();
});

发现错误:

我设法从 Chrome 控制台获取了这个:

错误:第 27 行 http://xxxxxxx/demos/uplift/assets/js/uplift/workers/uplift-worker.js :未捕获的网络错误:无法执行“发送” “XMLHttpRequest”:加载失败 'http://xxxxxxx/demos/uplift/assets/js/uplift/php/uplift.php'。

指向 Worker 脚本行:upliftRequest.send(chunk);

Firebug 并没有给我太多的工作,但这显示了中止的请求:

这显示了与请求一起发送的标头:

我最初认为这是服务器端的问题,所以我从 uplift.php 中删除了所有 PHP,并留下一个空白页面来简单地测试上传到浏览器的部分并发布请求,但问题仍然存在。

更新:

我开始认为我的托管服务提供商通过使用 Apache Mod 安全规则来限制请求速率 - 可能是为了防止我的 IP 以蛮力攻击服务器。除此之外,我的上传器在我的本地主机 (MAMP) 上运行良好。

我对我的新怀疑做了更多研究。如果我自制的上传插件在向我的主机发送多个文件/请求时遇到问题,那么肯定有一些其他流行的上传插件使用相同的技术并将文件发布到同一主机,也会在网上发布类似的投诉。这产生了一些好的结果,很多人支持我的经验。一个人使用 Uploadify HTML5(也发送单独的请求)将“大量图像”上传到同一主机,但他的请求也被阻止了。我想我最好联系他们,看看他们的速率限制是什么。

【问题讨论】:

    标签: javascript ajax file-upload xmlhttprequest


    【解决方案1】:

    可能的问题

    我认为这是一个服务器端问题,即使是普通的 php 文件。服务器将为每个请求打开一个新线程。在控制台中使用top 进行检查。

    你正在一个while循环中上传块,而不是等到上一个块上传完成..

    建议

    我会创建一个包含所有块的数组并执行upload(chunks) 并在那里管理并发,onreadystatechange 是处理数组中下一个块的好地方..

    【讨论】:

    • 感谢您的回复。我在请求中使用async: false,所以它应该等待前一个块完成后再尝试发送另一个块。
    • 啊,我明白了.. 但是您是否尝试过异步方式,并在onreadystatechange 回调中管理下一个块.. 比较行为会很有趣
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 2014-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    相关资源
    最近更新 更多