Gereksinimler ve Ön Hazırlık
Projenize başlamadan önce sisteminizde Node.js (LTS sürümü 20.x veya üzeri önerilir) kurulu olmalıdır. Ayrıca paket yönetimi için npm veya pnpm kullanabilirsiniz. Çalışma ortamınızı hazırlamak için aşağıdaki adımları takip edin:
- Node.js ve npm kurulumunu kontrol edin:
node -vvenpm -vkomutlarını çalıştırın. - Proje klasörünü oluşturun ve içine girin:
mkdir dosya-paneli && cd dosya-paneli - Gerekli paketleri kurun:
npm init -ykomutuylapackage.jsonoluşturun. - Bağımlılıkları yükleyin:
npm install express socket.io chokidar
Burada chokidar kütüphanesini kullanmamızın sebebi, Node.js'in yerel fs.watch metoduna göre çok daha kararlı ve platformlar arası uyumlu bir dosya izleme deneyimi sunmasıdır.
Sunucu Tarafı Kurulumu ve Socket.io Yapılandırması
Node.js sunucusu, hem HTTP isteklerini karşılamalı hem de WebSocket bağlantılarını yönetmelidir. Socket.io, bağlantı koptuğunda otomatik yeniden bağlanma ve düşük gecikmeli iletişim sağlar. İlk olarak temel sunucu yapısını kuruyoruz.
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = new Server(server);
io.on('connection', (socket) => {
console.log('Bir kullanıcı bağlandı: ' + socket.id);
socket.on('disconnect', () => {
console.log('Kullanıcı ayrıldı');
});
});
server.listen(3000, () => {
console.log('Sunucu http://localhost:3000 adresinde çalışıyor.');
});
Bu kod bloğu, temel bir HTTP sunucusu oluşturur ve üzerine Socket.io katmanını ekler. io.on('connection') bloğu, her yeni istemci bağlantısında tetiklenir ve bağlantı yönetimini sağlar.
Dosya Sistemi İzleme ve Canlı Güncellemeler
Dosya yönetim panelinin "canlı" olması için, sunucudaki bir klasörde gerçekleşen değişiklikleri (dosya ekleme, silme, isim değiştirme) anında istemcilere bildirmemiz gerekir. Bunun için chokidar kütüphanesini kullanacağız.
const chokidar = require('chokidar');
const path = require('path');
const watcher = chokidar.watch(path.join(__dirname, 'files'), {
persistent: true
});
watcher.on('all', (event, filePath) => {
const fileName = path.basename(filePath);
io.emit('file-update', { event, fileName });
});
Bu kod, files klasörünü sürekli izler. Bir dosya eklendiğinde veya silindiğinde file-update olayı tüm bağlı istemcilere yayınlanır. io.emit metodu, sunucuya bağlı olan tüm kullanıcılara mesaj gönderilmesini sağlar.
İstemci Tarafı: Socket.io Entegrasyonu
İstemci tarafında, sunucudan gelen canlı güncellemeleri dinlemeli ve DOM (Document Object Model) üzerinde gerekli güncellemeleri yapmalıyız. Basit bir HTML yapısı ile bu verileri listeleyelim.
const socket = io();
const fileList = document.getElementById('file-list');
socket.on('file-update', (data) => {
console.log('Güncelleme geldi:', data);
// Burada gelen veriye göre DOM güncellenir
const li = document.createElement('li');
li.textContent = `${data.event}: ${data.fileName}`;
fileList.appendChild(li);
});
Bu kod, sunucudan gelen file-update olayını dinler. Olay geldiğinde, sayfadaki liste öğesine yeni bir satır ekleyerek kullanıcının sayfayı yenilemesine gerek kalmadan değişikliği görmesini sağlar.
Dosya İşlemleri ve Güvenlik Önlemleri
Kullanıcıların panel üzerinden dosya oluşturmasına veya silmesine izin verirken, dizin geçişi (directory traversal) gibi saldırılara karşı dikkatli olmalıyız. Kullanıcıdan gelen dosya isimlerini doğrudan fs modülüne geçirmek güvenlik açığı yaratır.
const fs = require('fs');
socket.on('delete-file', (fileName) => {
// Güvenlik: Sadece dosya ismini al, yolu kısıtla
const safePath = path.join(__dirname, 'files', path.basename(fileName));
if (fs.existsSync(safePath)) {
fs.unlinkSync(safePath);
}
});
Yukarıdaki örnekte path.basename() kullanımı, kullanıcının ../../etc/passwd gibi yollarla sistem dosyalarına erişmesini engellemek için kritik bir güvenlik önlemidir.
Kritik Güvenlik Uyarısı: Üretim ortamında (production) dosya sistemine doğrudan erişim sağlayan API'ler oluştururken mutlaka kullanıcı yetkilendirmesi (JWT veya Session tabanlı) kullanın. Asla kullanıcıdan gelen veriyi doğrudan sistem komutu olarak çalıştırmayın.
Performans ve Yöntem Karşılaştırması
Canlı dosya yönetimi için kullanılan farklı yaklaşımların karşılaştırması aşağıdadır:
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| Socket.io | Düşük gecikme, çift yönlü iletişim | Sunucu kaynak tüketimi yüksektir |
| Polling (setInterval) | Basit uygulama | Yüksek ağ trafiği, gecikmeli veri |
| Server-Sent Events | Hafif, tek yönlü | Sadece sunucudan istemciye veri |
Sıkça Sorulan Sorular
Socket.io bağlantısı neden sürekli kopuyor?
Bu durum genellikle ağ yapılandırması veya sunucu tarafındaki "heartbeat" (kalp atışı) zaman aşımı ayarlarıyla ilgilidir. İstemci ve sunucu arasındaki bağlantının kararlılığı için proxy (Nginx vb.) kullanıyorsanız, WebSocket desteğinin açık olduğundan emin olun.
Birden fazla sunucu (cluster) kullanırsam ne olur?
Socket.io, varsayılan olarak tek bir sunucu örneğinde çalışır. Eğer uygulamanızı ölçeklendirip birden fazla sunucuya yayarsanız, @socket.io/redis-adapter kullanarak mesajların sunucular arasında iletilmesini sağlamalısınız.
Dosya yükleme (upload) işlemini nasıl eklerim?
Dosya yükleme için multer kütüphanesini kullanabilirsiniz. Dosya başarıyla yüklendikten sonra io.emit ile tüm istemcilere yeni dosyanın geldiğini bildirebilirsiniz.
Büyük dosyalar için WebSocket uygun mudur?
Hayır, WebSocket büyük binary verilerin iletimi için tasarlanmamıştır. Büyük dosyalar için geleneksel HTTP POST isteklerini kullanmalı, sadece dosya durumu güncellemelerini Socket.io üzerinden yapmalısınız.
XSS saldırılarına karşı nasıl önlem alırım?
İstemci tarafında DOM'a veri eklerken innerHTML yerine textContent kullanın. Bu, gelen dosya isimlerinin HTML olarak yorumlanmasını engelleyerek XSS saldırılarını önler.
Kod güvenliği sorumluluk reddi: Bu rehberdeki örnekler eğitim amaçlıdır. Uygulamanızı canlıya almadan önce tüm girdi doğrulamalarını (input validation) ve yetkilendirme mekanizmalarını (authentication/authorization) profesyonel standartlara göre yapılandırın.
Dağıtık Sistemlerde Ölçeklenebilirlik: Redis Adaptörü Kullanımı
Uygulamanız büyüdükçe ve kullanıcı sayısı arttıkça, tek bir Node.js sunucusu trafiği karşılamakta yetersiz kalabilir. Socket.io, çoklu sunucu (cluster) yapılarında mesajların tüm istemcilere ulaşmasını sağlamak için @socket.io/redis-adapter kütüphanesini kullanır. Bu sayede bir sunucuya bağlı olan istemci, diğer sunucudaki bir dosya değişikliğinden haberdar olabilir.
Redis adaptörünü kurmak için şu adımları izleyin:
npm install @socket.io/redis-adapter redis
Sunucu yapılandırmanızda Redis bağlantısını şu şekilde entegre edebilirsiniz:
const { createClient } = require("redis");
const { createAdapter } = require("@socket.io/redis-adapter");
const pubClient = createClient({ url: "redis://localhost:6379" });
const subClient = pubClient.duplicate();
Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
io.adapter(createAdapter(pubClient, subClient));
});
Canlı Dosya Yönetiminde Hata Ayıklama (Debugging) Stratejileri
Gerçek zamanlı uygulamalarda hata ayıklamak, geleneksel HTTP isteklerine göre daha karmaşıktır. Bağlantı kopmaları, paket kayıpları veya dosya izleme (watch) hatalarını tespit etmek için izlemeniz gereken yöntemler şunlardır:
- Socket.io Debug Modu: Sunucu tarafında
DEBUG=socket.io* node app.jskomutunu kullanarak tüm paket trafiğini konsolda görebilirsiniz. - Dosya Sistemi Olaylarını İzleme:
fs.watchveyachokidarkullanırken, işletim sistemi seviyesindeki kısıtlamaları (inotify limitleri) kontrol edin. Linux sistemlerde çok fazla dosya izlendiğindeENOSPChatası alabilirsiniz. - Bağlantı Durumunu İzleme: İstemci tarafında bağlantı kesintilerini yakalamak için
connect_errorolayını dinleyin.
// İstemci tarafı hata ayıklama örneği
socket.on("connect_error", (err) => {
console.error("Bağlantı hatası:", err.message);
// Kullanıcıya görsel bildirim gönderin
showToast("Sunucu ile bağlantı kesildi, tekrar deneniyor...");
});
// Sunucu tarafı dosya izleme hata yönetimi
const watcher = fs.watch('./uploads', (eventType, filename) => {
if (!filename) return;
console.log(`Dosya değişikliği: ${eventType} - ${filename}`);
});
watcher.on('error', (error) => {
console.error("Dosya izleyici hatası:", error);
});
Performans İpuçları ve Optimizasyon
Dosya yönetim panelinizin performansını artırmak için şu teknikleri uygulayın:
| Teknik | Açıklama |
|---|---|
| Debouncing | Dosya değişikliklerini anlık göndermek yerine 300ms'lik bir gecikme ekleyerek sunucu yükünü azaltın. |
| Binary Veri | Büyük dosya içeriklerini metin olarak değil, Buffer veya Blob formatında gönderin. |
| Namespace Kullanımı | Tüm olayları ana kanalda tutmak yerine io.of('/files') gibi namespace'ler kullanarak trafiği segmente edin. |
Özellikle chokidar gibi kütüphaneler kullanırken, awaitWriteFinish seçeneğini aktif ederek dosya yazma işlemi tamamen bitmeden tetiklenmesini engelleyebilir ve hatalı veri gönderiminin önüne geçebilirsiniz.
Sonuç
Node.js ve Socket.io kullanarak canlı bir dosya yönetim paneli oluşturmak, gerçek zamanlı web uygulamalarının temellerini anlamak için harika bir projedir. Bu rehberde dosya izleme, sunucu-istemci iletişimi ve temel güvenlik pratiklerini ele aldık. Bir sonraki adım olarak, bu yapıya kullanıcı yetkilendirme sistemi ekleyebilir veya dosya içeriklerini anlık olarak düzenleyebilecek bir "editör" modülü geliştirmeyi deneyebilirsiniz. Başarılar dileriz.

Yorumlar (0)
Yorum Yaz