在Node.js+Express中使用Multer上传前验证图片宽高
Got it, I totally get where you're coming from—having that pre-upload validation like you did in CodeIgniter makes way more sense than cleaning up files after they're already on your server. The key here is to avoid writing the file to disk until we've confirmed its dimensions, which we can do using Multer's memory storage combined with an efficient image processing library like sharp.
Here's a step-by-step solution tailored to your needs:
1. Install Required Packages
First, grab the libraries we'll use for upload handling and image validation:
npm install multer sharp
2. Set Up Custom File Filter with Dimension Checks
We'll use Multer's memoryStorage to temporarily hold the file in memory (instead of writing it to disk immediately), then use sharp to read its dimensions before allowing the upload to proceed.
const multer = require('multer'); const sharp = require('sharp'); const path = require('path'); const fs = require('fs/promises'); // Create uploads directory if it doesn't exist const ensureUploadsDir = async () => { const uploadsPath = path.join(__dirname, 'uploads'); try { await fs.access(uploadsPath); } catch { await fs.mkdir(uploadsPath); } }; ensureUploadsDir(); // Custom filter to validate image dimensions pre-upload const validateImageSize = async (req, file, cb) => { // First, verify the file is an image if (!file.mimetype.startsWith('image/')) { return cb(new Error('Only image files are allowed!'), false); } try { // Read image metadata (including dimensions) from the in-memory buffer const metadata = await sharp(file.buffer).metadata(); const { width, height } = metadata; // Define your required dimensions (70px × 40px here) const requiredWidth = 70; const requiredHeight = 40; if (width !== requiredWidth || height !== requiredHeight) { return cb( new Error(`Image must be exactly ${requiredWidth}px × ${requiredHeight}px. Received ${width}px × ${height}px`), false ); } // Dimensions are valid—allow the upload cb(null, true); } catch (err) { cb(new Error('Failed to validate image dimensions. Ensure the file is a valid image.'), false); } }; // Configure Multer with memory storage and our custom filter const upload = multer({ storage: multer.memoryStorage(), // Temporarily store file in memory fileFilter: validateImageSize, limits: { fileSize: 1 * 1024 * 1024 // Limit file size to 1MB to avoid memory overload } });
3. Create the Upload Route
Once validation passes, we'll write the in-memory file to your server's disk:
const express = require('express'); const app = express(); app.post('/upload-image', upload.single('image'), async (req, res) => { try { // Save the validated image from memory to disk const savePath = path.join(__dirname, 'uploads', req.file.originalname); await sharp(req.file.buffer).toFile(savePath); res.status(200).send('Image uploaded successfully!'); } catch (err) { res.status(500).send(`Failed to save image: ${err.message}`); } }); // Error handling middleware for upload/validation errors app.use((err, req, res, next) => { if (err instanceof multer.MulterError) { res.status(400).send(`Upload error: ${err.message}`); } else if (err) { res.status(400).send(err.message); } else { next(); } }); app.listen(3000, () => console.log('Server running on port 3000'));
Key Details to Note
- Memory storage benefit: This ensures the file never touches your disk unless it passes validation, matching your CodeIgniter workflow. If validation fails, the in-memory buffer is automatically garbage-collected.
- Memory limits: Always set a
fileSizecap to prevent large images from eating up your server's memory—adjust the value based on your use case. - Alternative with Jimp: If you prefer a simpler API, replace
sharpwithjimp—the core logic stays the same; you'll just swap the metadata reading step with Jimp'sread()method.
内容的提问来源于stack exchange,提问作者Gaurav Kumar

