ویژگی تصویر

آپلود چندین فایل به‌صورت هم‌زمان در Node.js — راهنمای کامل

  /  Node.js   /  آپلود چندین فایل به صورت هم زمان در Node.js
بنر تبلیغاتی الف
NodeJS - Node.js

در برنامه‌های وبی امروزی، آپلود هم‌زمان چندین فایل یکی از نیازهای رایج است؛ از آپلود عکس‌های گالری تا ارسال فایل‌های حجیم به‌صورت موازی به سرویس ذخیره‌سازی ابری. این مقاله به شما نشان می‌دهد چگونه در Node.js چندین فایل را به‌صورت امن، کارآمد و مقیاس‌پذیر آپلود کنید، بهترین ابزارها را معرفی می‌کند و مثال‌های عملی و بهینه‌سازی‌ها را توضیح می‌دهد.

چالش‌ها و نکات کلیدی

  • مدیریت حافظه: دریافت فایل‌ها در حافظه ممکن است باعث OutOfMemory شود.
  • جریان‌ها (Streams): استفاده از استریم‌ها برای خواندن و نوشتن فایل‌ها به‌صورت جزئی و کم‌هزینه است.
  • محدودیت اندازه و نوع فایل: اعتبارسنجی MIME نوع و حداکثر اندازه لازم است.
  • مقیاس‌پذیری: ارسال موازی به منابع خارجی (مثلاً S3) نیاز به مدیریت هم‌زمانی دارد.
  • امنیت: جلوگیری از آپلود فایل‌های مخرب و اسکن ویروس در موارد حساس.

ابزارهای متداول

کتابخانهنوعمناسب برای
multerMiddleware (Express)فرم‌های ساده و ذخیره محلی یا حافظه
busboyStreaming parserآپلودهای بزرگ، مستقیم به S3 یا دیسک
formidableParserسناریوهای پیچیده که نیاز به کنترل کامل دارند

مثال ساده با Multer (آپلود چند فایل)

const express = require('express');
const multer = require('multer');
const path = require('path');

const storage = multer.diskStorage({
  destination: (req, file, cb) => cb(null, 'uploads/'),
  filename: (req, file, cb) =>
    cb(null, Date.now() + '-' + file.originalname)
});

const upload = multer({
  storage,
  limits: { fileSize: 10 * 1024 * 1024 }, // 10MB per file
  fileFilter: (req, file, cb) => {
    if (!file.mimetype.startsWith('image/')) {
      return cb(new Error('Only images allowed'), false);
    }
    cb(null, true);
  }
});

const app = express();
app.post('/upload', upload.array('files', 10), (req, res) => {
  res.json({ uploaded: req.files.length });
});

app.listen(3000);

در این کد از multer با storage دیسکی استفاده کردیم. محدودیت اندازه و فیلتر نوع فایل تعیین شده‌اند. upload.array(‘files’, 10) تا 10 فایل را دریافت می‌کند و هر فایل بلافاصله روی دیسک نوشته می‌شود؛ بنابراین حافظه سرور کمتر استفاده می‌شود.

استریم به S3 با Busboy — روش بهینه برای فایل‌های بزرگ

const http = require('http');
const Busboy = require('busboy');
const { S3Client } = require('@aws-sdk/client-s3');
const { Upload } = require('@aws-sdk/lib-storage');

const s3 = new S3Client({ region: 'us-east-1' });

http.createServer((req, res) => {
  if (req.method === 'POST') {
    const busboy = new Busboy({ headers: req.headers });
    const uploads = [];

    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
      const upload = new Upload({
        client: s3,
        params: {
          Bucket: 'my-bucket',
          Key: `uploads/${Date.now()}-${filename}`,
          Body: file,
          ContentType: mimetype
        }
      });
      uploads.push(upload.done());
    });

    busboy.on('finish', async () => {
      try {
        const results = await Promise.allSettled(uploads);
        res.writeHead(200, { Connection: 'close' });
        res.end(JSON.stringify(results));
      } catch (err) {
        res.writeHead(500);
        res.end('Upload error');
      }
    });

    req.pipe(busboy);
  } else {
    res.writeHead(200);
    res.end('OK');
  }
}).listen(3000);

این مثال از Busboy برای پردازش multipart/form-data استفاده می‌کند و هر فایل را به‌صورت استریم مستقیم به S3 می‌فرستد. با این روش فایل‌ها در حافظه نگهداری نمی‌شوند و با AWS SDK v3 و Upload (که multipart را مدیریت می‌کند) آپلود قابل اطمینان انجام می‌شود. در پایان از Promise.allSettled استفاده شده تا وضعیت هر آپلود جداگانه گزارش شود.

کنترل هم‌زمانی (Concurrency)

اگر تعداد فایل‌ها زیاد باشد، ارسال تمام فایل‌ها به‌صورت هم‌زمان ممکن است منابع را اشباع کند. بهتر است با یک صف یا محدودیت هم‌زمانی کار کنید. می‌توانید از پکیج‌هایی مثل p-limit استفاده کنید یا خودتان یک pool ساده بنویسید.

const pLimit = require('p-limit');
const limit = pLimit(3); // max 3 concurrent uploads

const tasks = files.map(file => limit(() => uploadToS3(file)));
await Promise.all(tasks);

در این قطعه، حداکثر سه آپلود هم‌زمان اجرا می‌شود که از بارگذاری بیش از حد شبکه و ارجاع به منابع جلوگیری می‌کند. این الگو مخصوصاً وقتی سرویس مقصد محدودیت سرعت دارد مفید است.

بهترین شیوه‌ها و نکات امنیتی

  • همیشه محدودیت اندازه فایل (max file size) را تعیین کنید.
  • نوع فایل را بررسی کنید؛ برای حساسیت بالا از اسکن ویروس استفاده کنید.
  • از استریم‌ها بجای بارگذاری کامل در حافظه استفاده کنید.
  • برای سرویس‌های ابری از آپلود چندبخشی (multipart) و resume پشتیبانی کنید.
  • لاگ‌گذاری و گزارش خطا برای هر فایل جداگانه مفید است.

پیاده‌سازی گزارش پیشرفت (Progress) و UX

برای تجربه کاربری بهتر، اطلاعات پیشرفت آپلود را از سمت کلاینت به سرور منتقل کنید یا با وب‌سوکت/Socket.IO پیشرفت آپلود هر فایل را گزارش دهید. در سمت سرور با EventEmitter یا stream events می‌توان میزان منتقل‌شده را محاسبه و به کلاینت ارسال کرد.

نتیجه‌گیری و پیشنهاد عملی

برای اکثر پروژه‌ها اگر فایل‌ها کوچک و کم‌تعداد هستند، multer با ذخیره در دیسک کافی است. برای فایل‌های بزرگ یا نیاز به ارسال مستقیم به سرویس ابری، از Busboy یا سایر پارسرهای استریمینگ به همراه SDK سرویس ابری استفاده کنید. کنترل هم‌زمانی، اعتبارسنجی، و مدیریت خطا کلیدهای اجرای موفق آپلود چندفایلی در Node.js هستند.

در صورت نیاز می‌توانم مثال عملی‌تر با Resume Upload (tus)، یا پیاده‌سازی WebSocket برای گزارش زنده پیشرفت آماده کنم.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: