基于NodeJS与Busboy实现Firebase多图上传改造方案咨询
Refactoring Firebase Busboy Upload for Multi-Image Support
Got it, let's get your multi-image upload working! The core issue with your current code is that it uses single variables (like imageFileName, imageToBeUploaded) instead of collections to track multiple files. Here's a step-by-step refactor that fixes this:
Key Changes Made:
- Replaced single-file variables with an array to track all uploaded files
- Used
Promise.all()to wait for all uploads to complete successfully before returning URLs - Maintained your original validation logic for file types
- Updated the response to return an array of image URLs instead of a single one
Refactored Code
const { admin, db } = require("./admin"); const config = require("./config"); exports.uploadImages = (req, res, url, folder) => { const BusBoy = require("busboy"); const path = require("path"); const os = require("os"); const fs = require("fs"); const busboy = new BusBoy({ headers: req.headers }); // Array to hold info for all uploaded files let imageFiles = []; busboy.on("file", (fieldname, file, filename, encoding, mimetype) => { // Validate file type first if (mimetype !== "image/jpeg" && mimetype !== "image/png") { return res.status(400).json({ error: "Wrong file type submitted! Only JPG/PNG allowed." }); } // Generate unique filename for each image const imageExtension = filename.split(".").pop(); const imageFileName = `${Math.round(Math.random() * 1000000000)}.${imageExtension}`; const filepath = path.join(os.tmpdir(), imageFileName); // Store file details in our array imageFiles.push({ filepath, mimetype, filename: imageFileName }); // Pipe the incoming file to the temporary path file.pipe(fs.createWriteStream(filepath)); }); busboy.on("finish", async () => { try { // Upload all files in parallel using Promise.all const uploadPromises = imageFiles.map(file => admin.storage().bucket().upload(file.filepath, { destination: `${folder}/${file.filename}`, resumable: false, metadata: { metadata: { contentType: file.mimetype } } }) ); // Wait for all uploads to complete await Promise.all(uploadPromises); // Generate URLs for all uploaded images (fixed encoding for special characters) const imageUrls = imageFiles.map(file => `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${encodeURIComponent(`${folder}/${file.filename}`)}?alt=media` ); // Handle the user profile update case if needed (adjust for multi-image if required) if (url === `/users/${req.user.alias}`) { // Note: If you want to store multiple user images, change `imageUrl` to `imageUrls` in your Firestore doc await db.doc(`${url}`).update({ imageUrls }); return res.json({ message: "Images uploaded successfully!", imageUrls }); } else { return res.json({ message: "Images uploaded successfully!", imageUrls }); } } catch (err) { console.error(err); return res.status(500).json({ error: err.code }); } }); busboy.end(req.rawBody); };
Additional Notes:
- Error Handling: If any single upload fails,
Promise.all()will reject immediately and return an error. If you want to allow partial success (skip failed uploads instead of failing all), wrap each upload in a try/catch inside themap()function. - Firestore Update: The original code updates a single
imageUrlfield for user profiles. If you want to store multiple images for a user, make sure your Firestore document has animageUrlsarray field instead. - Filename Uniqueness: Using
Math.random()for filenames works, but for better reliability, consider using theuuidpackage (install withnpm install uuidthen useuuid.v4()to generate unique IDs).
内容的提问来源于stack exchange,提问作者Dromediansk
相关产品推荐
相关产品推荐

