Node.js İle Multer Kullanarak Resim Yükleme Ve Yeniden Boyutlandırma Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Bu projeyi başlatmadan önce bilgisayarınızda güncel bir Node.js sürümünün (2026 yılı standartları gereği LTS sürümü önerilir) yüklü olduğundan emin olun. Proje klasörünüzü oluşturun ve gerekli paketleri yükleyerek işe başlayın.

mkdir resim-yukleme-projesi
cd resim-yukleme-projesi
npm init -y
npm install express multer sharp

Yukarıdaki komutlar sırasıyla proje dizinini oluşturur, Node.js paket yöneticisini başlatır ve projemizin temel taşları olan Express (web framework), Multer (dosya yükleme) ve Sharp (görsel işleme) paketlerini kurar.

Multer ile Dosya Yükleme Yapılandırması

Multer, dosyaları doğrudan diske yazabileceği gibi bellekte (memory) de tutabilir. Yeniden boyutlandırma işlemi yapacağımız için dosyayı bellekte tutup işledikten sonra kaydetmek daha verimli bir yöntemdir. Aşağıdaki kod ile temel depolama ayarlarını yapalım.

const multer = require('multer');

// Dosyaları bellekte tutmak için storage yapılandırması
const storage = multer.memoryStorage();

// Sadece resim dosyalarına izin veren filtre
const fileFilter = (req, file, cb) => {
    if (file.mimetype.startsWith('image/')) {
        cb(null, true);
    } else {
        cb(new Error('Sadece resim dosyaları yüklenebilir!'), false);
    }
};

const upload = multer({ storage: storage, fileFilter: fileFilter });

Bu yapılandırma, yüklenen dosyanın bir resim olup olmadığını kontrol eder. Eğer kullanıcı resim dışı bir dosya yüklemeye çalışırsa Multer hata fırlatır, bu da güvenli bir dosya yönetimi için ilk savunma hattıdır.

Sharp ile Resim Yeniden Boyutlandırma

Yüklenen resimleri orijinal boyutlarında saklamak hem disk alanını tüketir hem de web sayfasının yavaş yüklenmesine neden olur. Sharp kütüphanesi, yüksek performanslı görsel işleme sağlar. Aşağıdaki fonksiyon, yüklenen buffer verisini işleyerek boyutlandırır.

const sharp = require('sharp');

async function resimBoyutlandir(buffer) {
    return await sharp(buffer)
        .resize(500, 500, { fit: 'cover' })
        .toFormat('jpeg')
        .jpeg({ quality: 80 })
        .toBuffer();
}

Bu fonksiyon, gelen görseli 500x500 piksel boyutuna getirir, formatı JPEG'e çevirir ve kaliteyi %80 seviyesine düşürerek dosya boyutunu optimize eder.

Express Rota Tanımlama ve Entegrasyon

Şimdi Multer ve Sharp'ı bir araya getiren ana rota (route) yapısını oluşturalım. Bu aşamada, kullanıcının gönderdiği dosyayı alıp işleyerek yerel bir klasöre kaydedeceğiz.

const express = require('express');
const fs = require('fs/promises');
const path = require('path');
const app = express();

app.post('/yukle', upload.single('resim'), async (req, res) => {
    try {
        if (!req.file) return res.status(400).send('Dosya bulunamadı.');

        const islenmisResim = await resimBoyutlandir(req.file.buffer);
        const kayitYolu = path.join(__dirname, 'uploads', `resim-${Date.now()}.jpg`);
        
        await fs.writeFile(kayitYolu, islenmisResim);
        res.send('Resim başarıyla yüklendi ve boyutlandırıldı.');
    } catch (error) {
        res.status(500).send(error.message);
    }
});

Bu kod bloğu, 'resim' isimli form alanından gelen dosyayı alır, resimBoyutlandir fonksiyonuna gönderir ve elde edilen veriyi 'uploads' klasörüne yazar.

Görsel İşleme Yöntemlerinin Karşılaştırılması

Yöntem Avantaj Dezavantaj
Multer + Sharp Çok hızlı, düşük bellek kullanımı Ek bağımlılık gerektirir
Canvas API Esnek çizim imkanı Daha yavaş ve yüksek CPU tüketimi
Jimp Saf JavaScript (kurulumsuz) Performans olarak Sharp'ın gerisinde

Güvenlik Uyarısı: Kullanıcıdan gelen dosya isimlerine asla güvenmeyin. Dosyaları kaydederken mutlaka benzersiz isimler (UUID veya Date.now()) kullanın. Ayrıca, 'uploads' klasörüne doğrudan erişimi kısıtlayın ve sunucunuzun bu klasördeki scriptleri çalıştırmadığından emin olun.

Sıkça Sorulan Sorular

1. Yüklenen dosyaların boyutunu nasıl sınırlarım?

Multer yapılandırmasında limits: { fileSize: 2 * 1024 * 1024 } parametresini kullanarak dosya boyutunu 2MB ile sınırlayabilirsiniz.

2. Neden bellekte (memory) saklamayı tercih ediyoruz?

Bellekte saklamak, dosyayı diske yazmadan önce Sharp ile işlememize olanak tanır. Bu, geçici dosya karmaşasını önler ve I/O işlemlerini azaltır.

3. Sharp kütüphanesi tüm sunucularda çalışır mı?

Sharp, libvips kütüphanesine bağımlıdır. Çoğu Linux dağıtımında sorunsuz çalışır, ancak Docker kullanıyorsanız Alpine veya Debian tabanlı imajlarda gerekli kütüphanelerin yüklü olduğundan emin olmalısınız.

4. Çoklu resim yüklemeyi nasıl yaparım?

upload.single('resim') yerine upload.array('resimler', 5) kullanarak aynı anda 5 dosyaya kadar yükleme yapabilirsiniz.

5. Hata yönetimi neden önemli?

Dosya yükleme işlemleri ağ kesintileri, disk doluluğu veya geçersiz dosya formatları gibi birçok hataya açıktır. Try-catch blokları kullanmak, uygulamanızın çökmesini engeller.

İleri Düzey İpuçları: Resim Optimizasyonu ve WebP Dönüşümü

Resim işleme süreçlerinde sadece boyutlandırma yapmak yeterli değildir. Kullanıcı deneyimini artırmak ve sayfa yüklenme hızlarını iyileştirmek için modern formatlara geçiş yapmak kritik bir önem taşır. Sharp kütüphanesi, resimleri JPEG veya PNG yerine çok daha düşük boyutlu ve yüksek kaliteli olan WebP formatına dönüştürmenize olanak tanır.

Aşağıdaki kod örneği, yüklenen bir resmi hem yeniden boyutlandırıp hem de WebP formatına çevirerek diske kaydetme işlemini göstermektedir:

const sharp = require('sharp');
const path = require('path');

async function processAndConvert(buffer, filename) {
  await sharp(buffer)
    .resize(800, 600)
    .webp({ quality: 80 })
    .toFile(path.join(__dirname, 'uploads', `${filename}.webp`));
}

Bu yaklaşımı kullanarak sunucunuzdaki depolama maliyetlerini düşürebilir ve tarayıcıların WebP desteğinden faydalanarak bant genişliği tasarrufu sağlayabilirsiniz.

Performans İzleme ve Hata Ayıklama

Node.js üzerinde resim işleme süreçleri CPU yoğunluklu işlemlerdir. Eğer uygulamanız aynı anda çok fazla resim işleme isteği alıyorsa, Event Loop'un bloke olmasını engellemeniz gerekir. Bu durumu yönetmek için aşağıdaki stratejileri uygulayabilirsiniz:

  • Worker Threads Kullanımı: Çok büyük resim dosyalarıyla çalışıyorsanız, ana iş parçacığını rahatlatmak için worker_threads modülünü kullanarak resim işleme görevlerini arka plana atın.
  • Dosya Sistemi İzleme: Yükleme klasörünüzün doluluk oranını düzenli olarak kontrol edin. Gereksiz biriken geçici dosyaları temizlemek için fs-extra kütüphanesi ile bir "cron job" oluşturun.
  • Hata Ayıklama (Debugging): Sharp hatalarını yakalamak için sharp.cache(false) komutunu geliştirme aşamasında kullanabilirsiniz. Bu, önbellekleme kaynaklı hataların önüne geçmenizi sağlar.

Aşağıdaki örnekte, bir hata ayıklama katmanı ile işlemin başarısını nasıl loglayabileceğinizi görebilirsiniz:

try {
  await sharp(req.file.buffer)
    .resize(500, 500)
    .toFile(outputPath);
  console.log('İşlem başarıyla tamamlandı:', req.file.originalname);
} catch (err) {
  console.error('Resim işleme hatası:', err.message);
  res.status(500).send('Resim işlenirken bir sorun oluştu.');
}

Bu teknikler, uygulamanızın sadece çalışır durumda olmasını değil, aynı zamanda yüksek trafik altında bile stabil kalmasını sağlar. Özellikle üretim ortamında (production), resimlerin işlenme sürelerini ölçmek için console.time ve console.timeEnd kullanarak darboğazları tespit etmeyi ihmal etmeyin.

Sonuç

Node.js, Multer ve Sharp kombinasyonu, modern web uygulamalarında resim yönetimi için en verimli yoldur. Bu rehberde, dosyaları güvenli bir şekilde almayı, doğrulamayı ve sunucu kaynaklarını koruyarak yeniden boyutlandırmayı öğrendiniz. Bir sonraki adım olarak, yüklenen bu resimleri AWS S3 veya Google Cloud Storage gibi bulut depolama servislerine aktarmayı deneyerek uygulamanızı ölçeklenebilir hale getirebilirsiniz.

Sorumluluk Reddi: Bu makaledeki kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce dosya izinlerini, sunucu güvenliğini ve hata yakalama mekanizmalarını projenizin özel ihtiyaçlarına göre detaylandırmanız önerilir.

Bu yazıya tepkinizi paylaşın:
Emre Çelik

Eğitici içerik tasarımı ve yapılandırılmış metin oluşturma konusunda deneyimliyim. Kullanıcıların doğrudan sonuca ulaşmasını sağlayan net ve yalın bir anlatım tarzım var.

Yorumlar (0)

Yorum Yaz