In this loop, “req.files.upload.length” returns file count when 0, or more than one files are uploaded, however when one file is uploaded “req.files.upload.length” returns file size. Why?
upload handler:
app.post('/upload', function(req, res){
console.log('file count: ' + req.files.upload.length);
var file;
var i = 0;
for(var x = 0; x < req.files.upload.length; x++){
file = req.files.upload[x];
console.log(file.name + ' (' + (file.size * 0.0009765625).toFixed(0) + ' kB, ' + file.type + ')');
};
console.log(req.files.upload.length + ' files uploaded to server');
res.redirect('/forms');
});
When I upload one file I get this error:
TypeError: Cannot read property 'name' of undefined
at /Users/frode/Dropbox/Nettsider/expressmal/app.js:296:20
at callbacks (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/express/lib/router/index.js:272:11)
at param (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/express/lib/router/index.js:246:11)
at pass (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/express/lib/router/index.js:253:5)
at Router._dispatch (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/express/lib/router/index.js:280:4)
at Object.handle (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/express/lib/router/index.js:45:10)
at Context.next (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/express/node_modules/connect/lib/http.js:204:15)
at Context.<anonymous> (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/passport/lib/passport/context/http/actions.js:64:8)
at SessionStrategy.pass (native)
at /Users/frode/Dropbox/Nettsider/expressmal/node_modules/passport/lib/passport/strategies/session.js:48:12
URIError: URI malformed
at /Users/frode/Dropbox/Nettsider/expressmal/node_modules/express/node_modules/connect/lib/middleware/static.js:119:14
at Object.static [as handle] (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/express/node_modules/connect/lib/middleware/static.js:60:5)
at next (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/express/node_modules/connect/lib/http.js:204:15)
at pass (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/express/lib/router/index.js:219:24)
at Router._dispatch (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/express/lib/router/index.js:280:4)
at Object.handle (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/express/lib/router/index.js:45:10)
at Context.next (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/express/node_modules/connect/lib/http.js:204:15)
at Context.<anonymous> (/Users/frode/Dropbox/Nettsider/expressmal/node_modules/passport/lib/passport/context/http/actions.js:64:8)
at SessionStrategy.pass (native)
at /Users/frode/Dropbox/Nettsider/expressmal/node_modules/passport/lib/passport/strategies/session.js:48:12
In Express/Connect, req.files
will be an object with the input[type=file]
name
attribute as key, and the content as the value. If there are more than one input[type=file]
with the same name
, it will be an array instead. If you control the view, i.e. the web page with the form
, you should be able to have either unique names for each file input, or know that you have more than one with the name "upload".
Update: I didn't think of the most obvious case, where the user has selected more than one file.
Update: Here's what req.files
will look like for two different cases:
One file:
req.files = {
upload: {
name: 'foo.txt'
length: 1024
}
}
Two files:
req.files = {
upload: [
{
name: 'foo.txt'
length: 1024
},
{
name: 'bar.txt'
length: 2048
}
]
}
As should be clear from this example, req.files.upload
will have a length
property in either case, but as you have found out they mean different things.
You probably want to iterate over an array in any case, to simplify your own code. This is easy to accomplish with [].concat
:
// Make sure that files is always an array
var files = [].concat(req.files.upload);
for(var x = 0; x < files.length; x++){
file = files[x];
// ...
}