Node.js图片上传报错:TypeError: Cannot read property 'length' of undefined
Hey there, let's sort out this upload error you're facing. That TypeError almost always pops up when handling multiple files with Formidable, and here's why and how to fix it:
Root Cause
When you set form.multiples = true, Formidable behaves differently based on how many files are uploaded:
- If multiple files are sent, it returns an array of file objects under your target field (e.g.,
files.images = [file1, file2]) - If only one file is sent, it returns a single file object instead of an array (e.g.,
files.images = file1)
So if you try to access files.yourFieldName.length when only one file is uploaded, you're trying to get the length of a single object (which doesn't have that property), hence the "Cannot read property 'length' of undefined" error.
Step-by-Step Fixes
1. Normalize Files to an Array
First, make sure you always work with an array, regardless of the number of files uploaded. Add this right after you get the files object:
// Replace 'yourFileField' with the actual name attribute from your frontend file input const targetField = 'yourFileField'; const uploadedFiles = Array.isArray(files[targetField]) ? files[targetField] : files[targetField] ? [files[targetField]] : [];
Now uploadedFiles will always be an array—empty if no files were sent, single-element if one file, or multiple elements for multiple files. You can safely access uploadedFiles.length now.
2. Verify Frontend-Backend Field Name Match
Double-check that the name attribute of your frontend file input exactly matches the field name you're accessing in files. For example:
- Frontend:
<input type="file" name="uploadedImages" multiple> - Backend: Must use
files.uploadedImages(notfiles.imagesor any other variation)
If they don't match, files.yourFieldName will be undefined, and accessing .length will throw the error.
3. Clean Up Your Existing Code
Here's your updated app.post('/upload') route with fixes applied:
app.post('/upload', urlencodedParser, function(req, res) { var form = new formidable.IncomingForm(); form.uploadDir = "C:/Users/Abdulrahman Afify/myapp/"; form.keepExtensions = true; form.multiples = true; form.parse(req, function(err, fields, files) { if (err) { // Fixed typo: "faild" → "failed", and used backticks for template string return res.json({ results: "failed", data: {}, message: `Cannot upload Files. Error is: ${err}` }); } // Define your actual file field name here const fileFieldName = 'uploadedImages'; // Normalize to array const uploadedFiles = Array.isArray(files[fileFieldName]) ? files[fileFieldName] : files[fileFieldName] ? [files[fileFieldName]] : []; if (uploadedFiles.length === 0) { return res.json({ results: "failed", data: {}, message: 'No files were selected for upload.' }); } // Example: Loop through files to process them uploadedFiles.forEach(file => { console.log(`Uploaded file: ${file.name}, saved to: ${file.path}`); // Add your file processing logic here (e.g., move to permanent directory) }); res.json({ results: "success", data: { files: uploadedFiles }, message: 'Files uploaded successfully.' }); }); });
Bonus: Remove Redundant Check
You don't need if (req.url == '/upload') inside the route handler—since this is already the /upload POST route, that check is unnecessary and can be removed.
内容的提问来源于stack exchange,提问作者Abdelrahman Afify

