File upload 何时检查node.js上载脚本中的文件大小/mimetype?

File upload 何时检查node.js上载脚本中的文件大小/mimetype?,file-upload,node.js,File Upload,Node.js,我在node.js中创建了一个上传脚本,使用的是express/employee。它基本上工作,但我想知道在哪里和什么时候检查上传的文件e。G对于最大文件大小,或者如果文件的mimetype实际上是允许的 我的程序如下所示: app.post('/', function(req, res, next) { req.form.on('progress', function(bytesReceived, bytesExpected) { // ... do stuff

我在node.js中创建了一个上传脚本,使用的是express/employee。它基本上工作,但我想知道在哪里和什么时候检查上传的文件e。G对于最大文件大小,或者如果文件的mimetype实际上是允许的

我的程序如下所示:

app.post('/', function(req, res, next) {
    req.form.on('progress', function(bytesReceived, bytesExpected) {
        // ... do stuff
    });

    req.form.complete(function(err, fields, files) {
        console.log('\nuploaded %s to %s',  files.image.filename, files.image.path);
        // ... do stuff    
    });
});
form.on('progress', function(bytesReceived, bytesExpected) {
    if (bytesReceived > MAX_UPLOAD_SIZE) {
        console.log('### ERROR: FILE TOO LARGE');
    }
});
// contains the path of the uploaded file, 
// is grabbed in the fileBegin event below
var tmpPath; 

form.on('progress', function validateMimetype(bytesReceived, bytesExpected) {
    var percent = (bytesReceived / bytesExpected * 100) | 0;

    // pretty basic check if enough bytes of the file are written to disk, 
    // might be too naive if the file is small!
    if (tmpPath && percent > 25) {
        var child = exec('file --mime-type ' + tmpPath, function (err, stdout, stderr) {
            var mimetype = stdout.substring(stdout.lastIndexOf(':') + 2, stdout.lastIndexOf('\n'));

            console.log('### file CALL OUTPUT', err, stdout, stderr);

            if (err || stderr) {
                console.log('### ERROR: MIMETYPE COULD NOT BE DETECTED');
            } else if (!ALLOWED_MIME_TYPES[mimetype]) {
                console.log('### ERROR: INVALID MIMETYPE', mimetype);
            } else {
                console.log('### MIMETYPE VALIDATION COMPLETE');
            }
        });

        form.removeListener('progress', validateMimetype);
    }
});

form.on('fileBegin', function grabTmpPath(_, fileInfo) {
    if (fileInfo.path) {
        tmpPath = fileInfo.path;
        form.removeListener('fileBegin', grabTmpPath);
    }
});
在我看来,检查mimetype/文件大小的唯一可行的地方是
complete
事件,在该事件中,我可以可靠地使用文件系统函数在
/tmp/
中获取上载文件的大小,但这似乎不是一个好主意,因为:

  • 可能是恶意/太大的文件已上载到我的服务器上
  • 用户体验很差-你观看上传进度只是为了被告知之后它不起作用

实施这一目标的最佳实践是什么?我在node.js中找到了很多文件上传的例子,但似乎没有一个能完成我需要的安全检查

在节点IRC和节点邮件列表的一些人的帮助下,我做了以下工作:

我使用强大的处理文件上传。使用
progress
事件,我可以检查最大文件大小,如下所示:

app.post('/', function(req, res, next) {
    req.form.on('progress', function(bytesReceived, bytesExpected) {
        // ... do stuff
    });

    req.form.complete(function(err, fields, files) {
        console.log('\nuploaded %s to %s',  files.image.filename, files.image.path);
        // ... do stuff    
    });
});
form.on('progress', function(bytesReceived, bytesExpected) {
    if (bytesReceived > MAX_UPLOAD_SIZE) {
        console.log('### ERROR: FILE TOO LARGE');
    }
});
// contains the path of the uploaded file, 
// is grabbed in the fileBegin event below
var tmpPath; 

form.on('progress', function validateMimetype(bytesReceived, bytesExpected) {
    var percent = (bytesReceived / bytesExpected * 100) | 0;

    // pretty basic check if enough bytes of the file are written to disk, 
    // might be too naive if the file is small!
    if (tmpPath && percent > 25) {
        var child = exec('file --mime-type ' + tmpPath, function (err, stdout, stderr) {
            var mimetype = stdout.substring(stdout.lastIndexOf(':') + 2, stdout.lastIndexOf('\n'));

            console.log('### file CALL OUTPUT', err, stdout, stderr);

            if (err || stderr) {
                console.log('### ERROR: MIMETYPE COULD NOT BE DETECTED');
            } else if (!ALLOWED_MIME_TYPES[mimetype]) {
                console.log('### ERROR: INVALID MIMETYPE', mimetype);
            } else {
                console.log('### MIMETYPE VALIDATION COMPLETE');
            }
        });

        form.removeListener('progress', validateMimetype);
    }
});

form.on('fileBegin', function grabTmpPath(_, fileInfo) {
    if (fileInfo.path) {
        tmpPath = fileInfo.path;
        form.removeListener('fileBegin', grabTmpPath);
    }
});
可靠地检查mimetype要困难得多。基本思想是使用
progress
事件,然后如果上传了足够多的文件,则使用
file--mime-type
调用并检查该外部命令的输出。它看起来是这样的:

app.post('/', function(req, res, next) {
    req.form.on('progress', function(bytesReceived, bytesExpected) {
        // ... do stuff
    });

    req.form.complete(function(err, fields, files) {
        console.log('\nuploaded %s to %s',  files.image.filename, files.image.path);
        // ... do stuff    
    });
});
form.on('progress', function(bytesReceived, bytesExpected) {
    if (bytesReceived > MAX_UPLOAD_SIZE) {
        console.log('### ERROR: FILE TOO LARGE');
    }
});
// contains the path of the uploaded file, 
// is grabbed in the fileBegin event below
var tmpPath; 

form.on('progress', function validateMimetype(bytesReceived, bytesExpected) {
    var percent = (bytesReceived / bytesExpected * 100) | 0;

    // pretty basic check if enough bytes of the file are written to disk, 
    // might be too naive if the file is small!
    if (tmpPath && percent > 25) {
        var child = exec('file --mime-type ' + tmpPath, function (err, stdout, stderr) {
            var mimetype = stdout.substring(stdout.lastIndexOf(':') + 2, stdout.lastIndexOf('\n'));

            console.log('### file CALL OUTPUT', err, stdout, stderr);

            if (err || stderr) {
                console.log('### ERROR: MIMETYPE COULD NOT BE DETECTED');
            } else if (!ALLOWED_MIME_TYPES[mimetype]) {
                console.log('### ERROR: INVALID MIMETYPE', mimetype);
            } else {
                console.log('### MIMETYPE VALIDATION COMPLETE');
            }
        });

        form.removeListener('progress', validateMimetype);
    }
});

form.on('fileBegin', function grabTmpPath(_, fileInfo) {
    if (fileInfo.path) {
        tmpPath = fileInfo.path;
        form.removeListener('fileBegin', grabTmpPath);
    }
});

新版本的Connect(2.x.)已经使用limit中间件将其烘焙到
bodyParser

我认为这样做更好,因为当请求超过最大限制时,您可以终止请求,而不是停止强大的解析器(并让请求“继续”)


关于limit中间件的更多信息:

@CIRK正在工作,但我只是在一些pet项目中使用了它,而不是在生产中使用。请求稍后在控制器中关闭(我使用express.js作为框架)。如果您感兴趣,可以在github上查看此项目的完整源代码:-虽然我从未完全完成过,但在node.js中这是一次有趣的冒险;)