javascript - 如何在强大(Node.js)中取消用户上传?

标签 javascript node.js file-upload express

我已经解决这个问题两天了,我被卡住了。我正在使用带有 Express 的 Node.js,并且我正在尝试实现一个上传表单。基本上,我希望表单执行以下操作:

  • 检查文件的大小,如果文件太大则取消上传(当我说取消时,我的意思是阻止任何进一步的数据写入磁盘并删除临时文件)

    <
  • 检查文件类型并确认它是正确的类型(.jpg、.png 等),如果不是,则停止进一步写入磁盘并删除临时文件。

目前,我的上传工作正常,当文件太大或与正确的类型不匹配时会发出错误,然后我使用 fs.unlink() 删除文件整个文件已写入磁盘。但我发现这种方法存在一个潜在问题:如果用户上传了一个巨大的文件(GB 大小)怎么办?使用我现在的方法,它最终会从我的机器中删除,但不会在浪费大量资源之后。所以基本上,我希望使用最少的资源来确认文件可以上传。这是我到目前为止的代码:

    var path = absolutePath + '/public/images/users/' + req.session.userId + '/';
    var maxSize = 3146000; // 3MB
    var form = new formidable.IncomingForm();
    form.uploadDir = path;
    form.keepExtensions = true;

    form.on('error', function(message) {
        if(message)
        {
            res.json({err: message});
        }
        else
        {
            res.json({err: 'Upload error, please try again'});
        }
    });

    form.on('fileBegin', function(name, file){
        if(form.bytesExpected > maxSize)
        {
            this.emit('error', 'Size must not be over 3MB');
        }
    });

    form.on('file', function(name, file) {
        var type = file.type;
        type = type.split('/');
        type = type[1];

        if(type != 'jpeg' && type != 'png' && type != 'gif')
        {
            this.emit('error', "JPG's, PNG's, GIF's only");
            fs.unlink(file.path);
        }
        else
        {
            fs.rename(file.path, path + 'profile.' + type);
        }
    });

    form.on('progress', function(bytesReceived, bytesExpected) {
            console.log(bytesReceived); //This is just to view progress
    });

    form.parse(req);

我也很困惑,因为根据 https://github.com/felixge/node-formidable 的文件,它说:

A request that experiences an error is automatically paused, you will have to manually call request.resume() if you want the request to continue firing 'data' events.

这很好,但我似乎无法让它工作。每当我发出“错误”时,“数据”事件就会一直触发直到完成。

尝试

我曾尝试在发生错误时取消请求,但无济于事。 req.pause() 对我没有任何帮助,req.end()req.abort() 给了我一个错误,说它是'不是一个方法,而 req.connection.destroy()req.connection.end() 只是发送了一个循环的 POST 请求。

最后的想法

所以我正在寻找的东西似乎应该是常见的,但过去两天我一直在互联网上搜索一个彻底的实现,但我似乎找不到任何东西。我的意思是,在整个上传后检查文件的大小和类型很简单,但是谁愿意浪费所有这些资源?更不用说恶意用户可以做的事情了。

我将继续工作,直到我得到我正在寻找的东西,但我认为这个问题可能与其他一些用户有关,希望我能得到一些帮助!

感谢您的宝贵时间。

最佳答案

我会尝试回答我自己的问题...

所以在对 Formidable 进行了一些尝试和错误之后,我干脆放弃了它并切换到 Multiparty .当发出一个巨大的错误时,多方实际上会取消上传。

我的解决方案

所以我的解决方案利用客户端大小和类型检查(代码中未显示)。然后将请求发送到服务器。在服务器上,我在写入磁盘之前再次检查文件大小和类型是否正确。我可以通过使用 Multiparty 的 part 事件来做到这一点。如果它们不正确,那么我只需发送一个带有 413 错误的响应。 (感谢 josh3736 澄清了浏览器中应该发生的事情。)发送回 413 后,浏览器的行为有点零星。对于我正在测试的浏览器,它只显示了一个 pending 发布请求。我认为这种行为是由于没有处理整个表单,因此,它不会接受任何响应。这似乎不是最优雅的处理方式,因为没有显示错误代码,但这种行为只会被绕过客户端检查的恶意用户遇到(我的网站依赖于 Javascript,所以所有用户都会拥有它)如果他们想使用我的网站,则启用)。这就是我的文字解决方案,现在是一些代码......

app.post('/profile/profile_pic', urlencoded, function (req, res) {

    var path = absolutePath + '/public/images/users/' + req.session.userId + '/';
    var maxSize = 3146000; // 3MB

    var options = {uploadDir: path};
    var form = new multiparty.Form();

    form.on('error', function(message) {
        res.status = 413;
        res.send(413, 'Upload too large');
        res.end();
    });

    form.on('file', function(name, file) {
        var type = file.headers['content-type'];
        type = type.split('/');
        type = type[1];
        fs.rename(file.path, path + 'profile.' + type);
        path = '/images/users/' + req.session.userId + '/profile.' + type;
    });

    form.on('part', function(part) {
        var type = part.headers['content-type'];
        var size = part.byteCount - part.byteOffset;

        if(type != 'image/jpeg' && type != 'image/png' && type != 'image/gif' != 'application/pdf' || size > maxSize)
        {
            this.emit('error');
        }
    });

    form.on('close', function(){
        res.json({err: 0, path: path});
    });

    form.parse(req);

});

关于javascript - 如何在强大(Node.js)中取消用户上传?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20553575/

相关文章:

javascript - nodejs中的异步函数

javascript - devDependency 会影响包大小吗?

javascript - 嵌套 HTML 按钮不会执行 javascript

javascript - 将单个值转换为数组

database - Windows平台下的Redis

javascript - 上传前预览字体

php - 在 Codeigniter 中上传文件问题

java - 为什么 servlet 在多部分请求中找不到 FileItem?

javascript - jquery var = 文本 + 数字

javascript - 空数组映射创建空值( Angular )