jfi*_*izz 12 javascript file-upload node.js 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);
Run Code Online (Sandbox Code Playgroud)
我也很困惑,因为根据https://github.com/felixge/node-formidable上的文件,它说:
遇到错误的请求会自动暂停,如果您希望请求继续触发"数据"事件,则必须手动调用request.resume().
这将是伟大的,但我似乎无法让它工作.每当我发出"错误"时,"数据"事件会一直持续到完成.
尝试
我已经尝试在发生错误时取消请求,但无济于事.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);
});
Run Code Online (Sandbox Code Playgroud)
要中止上传,正确的做法是关闭套接字.
req.socket.end();
Run Code Online (Sandbox Code Playgroud)
不幸的是,服务器想要中止正在进行的HTTP上传的情况是一团糟.
在这里做正确的,符合规范的事情就是尽早发送HTTP 413响应 - 也就是说,一旦检测到客户端发送的字节数多于您想要处理的字节数.在发送错误响应后是否终止套接字取决于您.这符合RFC 2616. [...]接下来发生的事情并不理想.
如果您打开套接字,所有浏览器(Chrome 30,IE 10,Firefox 21)将继续发送数据,直到整个文件上传为止.然后,只有这样,浏览器才会显示您的错误消息.这真的很糟糕,因为用户必须等待整个文件完成上传,才发现服务器拒绝了它.它也浪费你的带宽.
浏览器的当前行为违反了RFC2616§8.2.2:
发送消息体的HTTP/1.1(或更高版本)客户端应该在发送请求时监视网络连接的错误状态.如果客户端看到错误状态,它应该立即停止传输正文.如果正在使用"分块"编码发送正文(第3.6节),则可以使用零长度块和空拖车来过早标记消息的结尾.如果正文前面有Content-Length标头,则客户端必须关闭连接.
如果您在发送HTTP 413响应后立即关闭套接字,所有浏览器显然会立即停止上传,但它们当前显示"连接重置"错误(或类似),而不是您可能在响应中发送的任何HTML.
同样,这可能违反了规范(允许服务器提前发送响应并关闭连接),但我不希望浏览器在这里很快修复.
你看到一系列POST
请求的事实是可疑的.你在使用某种AJAX上传器吗?在提前关闭套接字后,它可能会自动重试上载.
归档时间: |
|
查看次数: |
7304 次 |
最近记录: |