Modern web uygulamalarında dosya yükleme, özellikle büyük boyutlu dosyaların yönetimi ve kullanıcı deneyimi açısından kritik bir öneme sahiptir. NestJS tabanlı bir projede AWS S3 kullanarak bu süreci nasıl hızlandırabileceğinizi ve ölçeklenebilir hale getirebileceğinizi merak ediyorsanız, doğru yerdesiniz. Bu makale, NestJS ile S3 entegrasyonunu en verimli şekilde sağlamanın yollarını adım adım açıklıyor.
Günümüzün dijital dünyasında, kullanıcıların beklentileri her geçen gün artıyor. Bir fotoğraf yükleme, bir belge paylaşma veya bir video kaydı ekleme gibi işlemlerin sorunsuz, hızlı ve güvenilir bir şekilde gerçekleşmesi, uygulamanızın başarısı için hayati önem taşıyor. Özellikle büyük boyutlu dosyalar söz konusu olduğunda, standart dosya yükleme yöntemleri hızla darboğaz haline gelebilir, sunucu kaynaklarını tüketebilir ve kullanıcı deneyimini olumsuz etkileyebilir. Bu noktada, AWS Simple Storage Service (S3) gibi bulut tabanlı depolama çözümleri devreye girer. S3, yüksek ölçeklenebilirlik, dayanıklılık ve erişilebilirlik sunarak dosya depolama ve dağıtım ihtiyaçlarınıza güçlü bir çözüm sunar. Ancak, S3’ün potansiyelini tam olarak kullanabilmek için, NestJS gibi modern bir backend framework’ü ile doğru ve verimli bir entegrasyon şarttır. Yanlış yapılandırılmış veya optimize edilmemiş bir yükleme mekanizması, hem altyapı maliyetlerinizi artırabilir hem de kullanıcılarınızın uygulamanızdan uzaklaşmasına neden olabilir. Dolayısıyla, verimli S3 dosya yüklemeleri sadece bir performans iyileştirmesi değil, aynı zamanda işletme sürekliliği ve kullanıcı memnuniyeti için stratejik bir gerekliliktir.
Verimlilik, bu bağlamda birçok farklı boyutu kapsar. Örneğin, küçük dosyaların anında yüklenip erişilebilir olması, kullanıcıların hızlı geri bildirim almasını sağlar. Büyük dosyaların ise parçalara ayrılarak paralel bir şekilde yüklenmesi veya doğrudan istemciden S3’e gönderilmesi, sunucu üzerindeki yükü hafifletirken genel yükleme süresini dramatik bir şekilde kısaltabilir. Ayrıca, hata toleransı ve kesinti durumlarında yüklemeye devam edebilme yeteneği de, özellikle zayıf internet bağlantılarına sahip kullanıcılar için vazgeçilmezdir. Bu optimizasyonlar sadece son kullanıcı deneyimini iyileştirmekle kalmaz, aynı zamanda backend sunucularınızın daha az CPU ve bellek kullanmasını sağlayarak operasyonel maliyetlerinizi düşürür. Sürekli artan veri hacimleri ve kullanıcı sayılarıyla birlikte, NestJS uygulamalarınızda S3 dosya yüklemelerinin doğru bir şekilde ele alınması, uygulamanızın gelecekteki büyümesini ve ölçeklenebilirliğini doğrudan etkileyecektir. Bu makalenin ilerleyen bölümlerinde, bu verimlilik hedeflerine ulaşmak için kullanabileceğiniz farklı stratejileri ve pratik uygulama yöntemlerini detaylıca inceleyeceğiz.
S3 ve NestJS Entegrasyonunun Temelleri: Hızlı Bir Başlangıç Kılavuzu
NestJS ile AWS S3 entegrasyonuna başlamak, modern uygulamalarınızın dosya depolama ihtiyaçlarını karşılamak için atacağınız ilk ve en önemli adımdır. Öncelikle, AWS S3’ün ne olduğunu ve neden bu kadar popüler olduğunu anlamakla başlayalım. AWS S3 (Simple Storage Service), Amazon Web Services tarafından sunulan nesne depolama hizmetidir. Sınırsız ölçeklenebilirlik, %99.999999999 (on bir dokuz) dayanıklılık ve yüksek erişilebilirlik gibi özellikleriyle bilinir. S3, web siteleri, mobil uygulamalar, yedekleme ve arşivleme gibi birçok farklı senaryoda kullanılır. NestJS ise, Node.js tabanlı, TypeScript ile geliştirilmiş, oldukça modüler ve ölçeklenebilir bir backend framework’üdür. Geleneksel olarak Express.js üzerinde çalışır, ancak kendine özgü bir mimari ve güçlü bir bağımlılık enjeksiyon sistemi sunar. Bu iki teknolojiyi bir araya getirmek, güçlü ve esnek bir dosya yükleme altyapısı kurmanızı sağlar.
Entegrasyonun temel adımları genellikle AWS SDK’nın kurulması ve yapılandırılmasıyla başlar. İlk olarak, NestJS projenize AWS SDK’yı eklemelisiniz. Bunun için terminalinizde aşağıdaki komutu çalıştırın:
npm install @aws-sdk/client-s3 @aws-sdk/lib-storage
# veya yarn add @aws-sdk/client-s3 @aws-sdk/lib-storage
Bu paketler, S3 ile etkileşim kurmak için gerekli sınıfları ve işlevleri içerir. Ardından, NestJS uygulamanızda S3 istemcisini yapılandırmanız gerekir. Bu genellikle bir modül (örneğin, S3Module) veya bir servis (örneğin, S3Service) aracılığıyla yapılır. Ortam değişkenlerini kullanarak AWS kimlik bilgilerini (access key ID ve secret access key), bölgeyi (region) ve varsayılan S3 bucket adını güvenli bir şekilde saklamak en iyi uygulamadır. Örneğin, bir S3Service içinde S3 istemcisini şu şekilde başlatabilirsiniz:
// s3.service.ts
import { Injectable } from '@nestjs/common';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { Upload } from '@aws-sdk/lib-storage';
import { ConfigService } from '@nestjs/config'; // Ortam değişkenleri için
@Injectable()
export class S3Service {
private s3Client: S3Client;
private readonly bucketName: string;
constructor(private configService: ConfigService) {
this.bucketName = this.configService.get('AWS_S3_BUCKET_NAME');
this.s3Client = new S3Client({
region: this.configService.get('AWS_S3_REGION'),
credentials: {
accessKeyId: this.configService.get('AWS_ACCESS_KEY_ID'),
secretAccessKey: this.configService.get('AWS_SECRET_ACCESS_KEY'),
},
});
}
async uploadFile(file: Express.Multer.File): Promise {
const uniqueFileName = ${Date.now()}-${file.originalname};
const params = {
Bucket: this.bucketName,
Key: uniqueFileName,
Body: file.buffer,
ContentType: file.mimetype,
ACL: 'public-read', // İsteğe bağlı, dosyanın herkese açık olmasını sağlar
};
try {
await this.s3Client.send(new PutObjectCommand(params));
const fileUrl = https://${this.bucketName}.s3.${this.configService.get('AWS_S3_REGION')}.amazonaws.com/${uniqueFileName};
return fileUrl;
} catch (error) {
console.error('S3 Yükleme Hatası:', error);
throw new Error('Dosya yüklenirken bir hata oluştu.');
}
}
}
Bu örnekte, S3Service S3 istemcisini başlatır ve basit bir uploadFile metodu sunar. Bu metod, bir Express.Multer.File objesini alır (NestJS'te dosya yüklemek için genellikle multer kullanılır), dosyaya benzersiz bir ad verir ve S3'e yükler. ACL: 'public-read' dikkat çekicidir; bu, yüklenen dosyanın herkese açık olmasını sağlar. Güvenlik gereksinimlerinize göre bu ayarı değiştirebilirsiniz. ConfigService kullanımı, hassas bilgilerin doğrudan koda yazılmasını önler ve uygulamanızı daha güvenli hale getirir. Son olarak, bu servisi bir controller içinde kullanarak bir HTTP endpoint'i aracılığıyla dosya yüklemeyi tetikleyebilirsiniz:
// app.controller.ts
import { Controller, Post, UseInterceptors, UploadedFile } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { S3Service } from './s3.service';
@Controller('files')
export class AppController {
constructor(private readonly s3Service: S3Service) {}
@Post('upload')
@UseInterceptors(FileInterceptor('file')) // 'file' form alanının adıdır
async uploadFile(@UploadedFile() file: Express.Multer.File) {
if (!file) {
throw new Error('Yüklenecek dosya bulunamadı.');
}
const fileUrl = await this.s3Service.uploadFile(file);
return { message: 'Dosya başarıyla yüklendi!', url: fileUrl };
}
}
Bu temel yapılandırma ile küçük ve orta boyutlu dosyaları NestJS uygulamanız üzerinden güvenli bir şekilde S3'e yükleyebilirsiniz. Ancak, büyük dosyalar veya yüksek yükleme trafiği durumunda daha gelişmiş tekniklere ihtiyacınız olacaktır. Bu konuları makalenin ilerleyen bölümlerinde detaylandıracağız.
Küçük ve Orta Boyutlu Dosyalar İçin NestJS S3 Yükleme Optimizasyonu Nasıl Yapılır?
Küçük ve orta boyutlu dosyaların (genellikle birkaç megabayta kadar olan görseller, belgeler vb.) yüklenmesi, çoğu zaman yukarıda bahsettiğimiz temel yöntemle yeterince hızlı ve verimli olabilir. Ancak bu senaryolarda bile performansı daha da artırmak ve kullanıcı deneyimini iyileştirmek için bazı optimizasyonlar yapılabilir. Özellikle çok sayıda küçük dosyanın aynı anda yüklendiği durumlar veya düşük bant genişliğine sahip kullanıcılar için bu optimizasyonlar kritik hale gelebilir.
İlk olarak, dosyanın sunucu belleğinde geçici olarak tutulduğu "buffer tabanlı yüklemeler" bu boyutlardaki dosyalar için oldukça yaygındır. multer kütüphanesi bu yaklaşımı kolaylaştırır. multer'ı yapılandırırken, dosyaların diske yazılmadan doğrudan bellekte tutulmasını sağlamak için memoryStorage'ı kullanabiliriz. Bu, disk I/O'dan kaynaklanan gecikmeleri ortadan kaldırarak yükleme süresini bir miktar kısaltabilir. Ancak, dikkatli olunmalıdır; çok fazla dosya veya çok büyük dosyalar aynı anda belleğe alındığında sunucu belleği hızla tükenebilir ve uygulama çökebilir. Bu nedenle, multer içinde dosya boyutu limitleri belirlemek önemlidir.
// src/config/multer.config.ts
import { MulterOptions } from '@nestjs/platform-express/multer/interfaces/multer-options.interface';
import { memoryStorage } from 'multer';
export const multerOptions: MulterOptions = {
storage: memoryStorage(), // Dosyayı bellekte tutar
limits: {
fileSize: 5 * 1024 * 1024, // 5 MB dosya boyutu limiti
},
fileFilter: (req, file, cb) => {
if (!file.mimetype.match(/\/(jpg|jpeg|png|gif|pdf)$/)) { // Sadece belirli türlere izin ver
cb(new Error('Desteklenmeyen dosya türü'), false);
} else {
cb(null, true);
}
},
};
// app.controller.ts (örnek kullanım)
import { Controller, Post, UseInterceptors, UploadedFile } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { S3Service } from './s3.service';
import { multerOptions } from './config/multer.config'; // Multer konfigürasyonunu import edin
@Controller('files')
export class AppController {
constructor(private readonly s3Service: S3Service) {}
@Post('upload-small')
@UseInterceptors(FileInterceptor('file', multerOptions))
async uploadSmallFile(@UploadedFile() file: Express.Multer.File) {
if (!file) {
throw new Error('Yüklenecek dosya bulunamadı.');
}
const fileUrl = await this.s3Service.uploadFile(file); // S3Service'iniz hala aynı kalabilir
return { message: 'Küçük dosya başarıyla yüklendi!', url: fileUrl };
}
}
memoryStorage kullanırken, sunucunuzun belleğini tüketmemek için limits.fileSize özelliğini mutlaka belirleyin. Aksi takdirde, kötü niyetli yüklemeler veya beklenenden büyük dosyalar sunucunuzu çökertme riski taşır.
Bunun yanı sıra, yükleme işleminin güvenilirliğini artırmak için hata yönetimi ve tekrar deneme (retry) mekanizmaları geliştirmek faydalıdır. Ağ kesintileri veya S3 tarafındaki geçici sorunlar nedeniyle yüklemeler başarısız olabilir. AWS SDK genellikle dahili retry mekanizmalarına sahip olsa da, uygulamanız seviyesinde daha akıllı retry stratejileri (örneğin, exponential backoff ile) uygulayarak dayanıklılığı artırabilirsiniz. Bu, özellikle gecikmeli veya değişken ağ koşullarında yükleme başarısızlıklarının önüne geçmeye yardımcı olur. Örneğin, S3'e yükleme yapan fonksiyonunuzu bir try-catch bloğu içine alarak, belirli hata kodlarında yüklemeyi birkaç kez tekrar deneyebilirsiniz.
Son olarak, yüklenen dosyaların kullanıcılara daha hızlı ulaşmasını sağlamak için bir İçerik Dağıtım Ağı (CDN) entegrasyonu düşünülebilir. AWS CloudFront, S3 ile sorunsuz bir şekilde entegre olur. Dosyalarınızı S3'e yükledikten sonra, CloudFront dağıtımınızın önbellekleme yetenekleri sayesinde, kullanıcılar coğrafi olarak kendilerine en yakın uç noktadan (edge location) dosyaları alırlar. Bu, özellikle global bir kullanıcı kitleniz varsa, yüklenen içeriğin indirme hızını önemli ölçüde artırır. CloudFront, S3'teki nesneleri ilk istekle önbelleğine alır ve sonraki istekleri doğrudan kendi önbelleğinden sunar, bu da S3 istek maliyetlerinizi de düşürebilir. Küçük resimler, ikonlar, CSS ve JavaScript dosyaları gibi sık erişilen statik içerikler için CDN kullanımı vazgeçilmezdir. NestJS tarafında CDN'ye özel bir kod yazmanıza gerek yoktur, sadece S3'e yükledikten sonra oluşan URL'yi CloudFront dağıtımınızın domain'i ile değiştirmeniz yeterli olacaktır.
Büyük Dosyaları NestJS ile S3'e Verimli Bir Şekilde Nasıl Yükleyebiliriz?
Büyük boyutlu dosyalar (örneğin, video, yüksek çözünürlüklü görseller, yedekleme dosyaları) söz konusu olduğunda, buffer tabanlı yaklaşımlar yetersiz kalır ve sunucu kaynaklarını hızla tüketir. Bu tür senaryolarda "stream tabanlı yüklemeler" ve "multipart upload" teknikleri devreye girer. Bu yöntemler, dosyayı küçük parçalara bölerek veya doğrudan akış halinde S3'e ileterek hem bellek kullanımını optimize eder hem de yükleme süresini kısaltır.
Stream tabanlı yüklemeler, dosyanın tamamını belleğe almak yerine, gelen veriyi doğrudan okuyup S3'e iletmeyi içerir. Bu, sunucunun dosyanın tamamını geçici olarak depolamasına gerek kalmadığı için özellikle bellek açısından oldukça verimlidir. NestJS'te multer ile dosya yüklerken, memoryStorage yerine diskStorage kullanarak veya hiç storage belirtmeden, dosyanın bir stream olarak elde edilmesini sağlayabiliriz. Ancak, S3'e stream halinde yüklemek için AWS SDK'nın Upload sınıfını kullanmak en uygun yöntemlerden biridir. Bu sınıf, dosyanın boyutuna göre otomatik olarak "multipart upload" işlemini yönetir.
// s3.service.ts - Büyük dosya yükleme için metod
import { Injectable } from '@nestjs/common';
import { S3Client } from '@aws-sdk/client-s3';
import { Upload } from '@aws-sdk/lib-storage';
import { ConfigService } from '@nestjs/config';
import * as crypto from 'crypto'; // Benzersiz isimler için
@Injectable()
export class S3Service {
private s3Client: S3Client;
private readonly bucketName: string;
private readonly region: string;
constructor(private configService: ConfigService) {
this.bucketName = this.configService.get('AWS_S3_BUCKET_NAME');
this.region = this.configService.get('AWS_S3_REGION');
this.s3Client = new S3Client({
region: this.region,
credentials: {
accessKeyId: this.configService.get('AWS_ACCESS_KEY_ID'),
secretAccessKey: this.configService.get('AWS_SECRET_ACCESS_KEY'),
},
});
}
async uploadLargeFile(file: Express.Multer.File): Promise {
const fileName = ${crypto.randomBytes(16).toString('hex')}-${file.originalname};
const parallelUploads = new Upload({
client: this.s3Client,
params: {
Bucket: this.bucketName,
Key: fileName,
Body: file.stream, // Dosya akışını doğrudan kullanıyoruz
ContentType: file.mimetype,
ACL: 'public-read',
},
queueSize: 4, // Kaç parçanın paralel yükleneceğini belirler
partSize: 1024 * 1024 * 5, // Her bir parçanın boyutu (5 MB)
leavePartsOnError: false, // Hata durumunda tamamlanmamış parçaları sil
});
parallelUploads.on('httpUploadProgress', (progress) => {
console.log(Yükleme ilerlemesi: %${Math.round((progress.loaded / progress.total) * 100)});
// İstemciye WebSocket veya SSE ile ilerleme bilgisini gönderebilirsiniz
});
try {
const result = await parallelUploads.done();
const fileUrl = https://${this.bucketName}.s3.${this.region}.amazonaws.com/${fileName};
return fileUrl;
} catch (error) {
console.error('Büyük dosya S3 yükleme hatası:', error);
throw new Error('Büyük dosya yüklenirken bir hata oluştu.');
}
}
}
// app.controller.ts - Büyük dosya yükleme endpoint'i
import { Controller, Post, UseInterceptors, UploadedFile } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { S3Service } from './s3.service';
@Controller('files')
export class AppController {
constructor(private readonly s3Service: S3Service) {}
@Post('upload-large')
@UseInterceptors(FileInterceptor('file')) // Multer varsayılan olarak stream olarak iletir eğer storage belirtilmezse
async uploadLargeFile(@UploadedFile() file: Express.Multer.File) {
if (!file) {
throw new Error('Yüklenecek dosya bulunamadı.');
}
const fileUrl = await this.s3Service.uploadLargeFile(file);
return { message: 'Büyük dosya başarıyla yüklendi!', url: fileUrl };
}
}
Yukarıdaki örnekte Upload sınıfı, dosyayı otomatik olarak parçalara bölerek paralel bir şekilde yükler. queueSize parametresi aynı anda kaç parçanın yükleneceğini, partSize ise her bir parçanın boyutunu belirler. Bu, özellikle yüksek bant genişliğine sahip sunucular için yükleme hızını önemli ölçüde artırabilir. on('httpUploadProgress') olayı sayesinde, yükleme ilerlemesini izleyebilir ve bu bilgiyi istemcilere geri bildirim olarak sunabilirsiniz, bu da kullanıcı deneyimi açısından çok değerlidir.
Multipart Upload, 5 MB'tan büyük dosyalar için S3 tarafından önerilen bir yöntemdir. Dosya, birden fazla küçük parçaya bölünür. Bu parçalar ayrı ayrı S3'e yüklenir ve ardından S3 bu parçaları tek bir dosya halinde birleştirir. Bu yaklaşımın temel faydaları şunlardır:
- Kesintiden Devam Edebilme: Bir parça yüklemesi başarısız olursa, sadece o parçayı tekrar yüklemek yeterlidir, tüm dosyayı baştan yüklemeye gerek kalmaz.
- Paralellik: Birden fazla parçayı aynı anda yükleyerek genel yükleme süresini kısaltabilir.
- Daha Hızlı Hata Tespiti: Küçük parçalardaki hatalar daha hızlı tespit edilebilir.
AWS SDK'nın Upload sınıfı, bu karmaşık süreci sizin için soyutlar ve kolayca yönetmenizi sağlar. Bu sayede, NestJS uygulamanız büyük dosyaları bile etkili ve verimli bir şekilde S3'e aktarabilir, aynı zamanda sunucu kaynaklarınızı minimumda tutar. Bu yöntem, özellikle video düzenleme platformları, yedekleme hizmetleri veya büyük veri setlerinin işlendiği uygulamalar için vazgeçilmezdir.
Presigned URL'ler ile Doğrudan S3 Yüklemesi: Güvenlik ve Performansı Bir Arada Nasıl Sağlarız?
Şimdiye kadar ele aldığımız yöntemlerde, dosya yükleme işlemi NestJS backend sunucunuz üzerinden S3'e yapılıyordu. Bu, küçük dosyalar için kabul edilebilir olsa da, büyük dosyalar veya yüksek trafikli uygulamalar için NestJS sunucusu üzerinde gereksiz bir yük oluşturur. Her dosya önce istemciden sunucuya, ardından sunucudan S3'e aktarılır. Bu çift aktarım, gecikmeyi artırır, sunucu kaynaklarını (CPU, bellek, ağ bant genişliği) tüketir ve maliyetleri yükseltir.
İşte bu noktada Presigned URL'ler devreye girer. Presigned URL, belirli bir S3 nesnesi üzerinde belirli bir süre boyunca (genellikle birkaç dakika) belirli bir işlem (yükleme, indirme vb.) yapmaya izin veren, geçici ve güvenli bir URL'dir. Temel fikir şudur: İstemci (tarayıcı veya mobil uygulama), NestJS sunucusundan bir yükleme için Presigned URL talep eder. NestJS sunucusu, kendi AWS kimlik bilgilerini kullanarak bu URL'yi oluşturur ve istemciye geri gönderir. İstemci daha sonra bu Presigned URL'i kullanarak dosyayı doğrudan S3'e yükler. Bu sayede dosya, NestJS sunucunuz üzerinden geçmek zorunda kalmaz.
Presigned URL'lerin Avantajları:
- Performans İyileştirmesi: Dosya doğrudan istemciden S3'e gittiği için sunucu üzerinde aktarım yükü ortadan kalkar. Bu, özellikle büyük dosyalar için yükleme sürelerini önemli ölçüde azaltır.
- Sunucu Yükünü Azaltma: NestJS sunucunuz sadece URL'yi oluşturmakla meşgul olur, dosyanın kendisini işlemez. Bu, sunucunuzun daha fazla eşzamanlı isteği yönetmesine olanak tanır.
- Maliyet Optimizasyonu: Sunucu kaynaklarının daha az kullanılması, altyapı maliyetlerinde tasarruf sağlar.
- Güvenlik: Presigned URL'ler sınırlı bir süre geçerlidir ve sadece belirli bir işlemi (örneğin PUT) gerçekleştirmeye yetkilidir. Bu sayede AWS kimlik bilgileriniz istemciye asla açık edilmez.
NestJS Tarafında Presigned URL Oluşturma
NestJS'te Presigned URL oluşturmak için AWS SDK'nın @aws-sdk/s3-request-presigner paketini kullanabiliriz:
// s3.service.ts - Presigned URL oluşturma metodu
import { Injectable } from '@nestjs/common';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { ConfigService } from '@nestjs/config';
import * as crypto from 'crypto';
@Injectable()
export class S3Service {
private s3Client: S3Client;
private readonly bucketName: string;
private readonly region: string;
constructor(private configService: ConfigService) {
this.bucketName = this.configService.get('AWS_S3_BUCKET_NAME');
this.region = this.configService.get('AWS_S3_REGION');
this.s3Client = new S3Client({
region: this.region,
credentials: {
accessKeyId: this.configService.get('AWS_ACCESS_KEY_ID'),
secretAccessKey: this.configService.get('AWS_SECRET_ACCESS_KEY'),
},
});
}
async getPresignedUploadUrl(originalFileName: string, fileType: string): Promise {
const uniqueFileName = ${crypto.randomBytes(16).toString('hex')}-${originalFileName};
const command = new PutObjectCommand({
Bucket: this.bucketName,
Key: uniqueFileName,
ContentType: fileType,
ACL: 'public-read', // Veya istediğiniz bir ACL
});
const presignedUrl = await getSignedUrl(this.s3Client, command, {
expiresIn: 300, // URL 300 saniye (5 dakika) geçerli olacak
});
return { url: presignedUrl, key: uniqueFileName };
}
}
// app.controller.ts - Presigned URL endpoint'i
import { Controller, Post, Body } from '@nestjs/common';
import { S3Service } from './s3.service';
interface GetPresignedUrlDto {
fileName: string;
fileType: string;
}
@Controller('files')
export class AppController {
constructor(private readonly s3Service: S3Service) {}
@Post('presigned-url')
async getPresignedUrl(@Body() dto: GetPresignedUrlDto) {
const { url, key } = await this.s3Service.getPresignedUploadUrl(dto.fileName, dto.fileType);
return { uploadUrl: url, fileKey: key };
}
}
İstemci Tarafında Kullanım (Kavramsal)
İstemci tarafında (örneğin React, Vue, Angular uygulamaları), bu URL'yi kullanarak dosyayı doğrudan S3'e yüklemek için fetch API'si veya Axios gibi bir HTTP istemcisi kullanabilirsiniz. İşte basit bir JavaScript örneği:
// İstemci tarafı JavaScript (örnek)
async function uploadFileDirectlyToS3(file) {
// 1. NestJS backend'inden Presigned URL'i al
const response = await fetch('/files/presigned-url', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ fileName: file.name, fileType: file.type }),
});
const { uploadUrl, fileKey } = await response.json();
// 2. Presigned URL'i kullanarak dosyayı doğrudan S3'e yükle
await fetch(uploadUrl, {
method: 'PUT',
headers: {
'Content-Type': file.type, // Dosyanın doğru Content-Type'ını belirtmek önemli
},
body: file, // File objesinin kendisini body olarak gönderiyoruz
});
console.log('Dosya doğrudan S3\'e yüklendi. S3 Key:', fileKey);
return https://YOUR_BUCKET_NAME.s3.YOUR_REGION.amazonaws.com/${fileKey}; // Yüklenen dosyanın nihai URL'si
}
// Örnek kullanım: Bir input[type="file"] elementinden dosya seçildiğinde
document.getElementById('fileInput').addEventListener('change', async (event) => {
const file = event.target.files[0];
if (file) {
try {
const fileUrl = await uploadFileDirectlyToS3(file);
console.log('Yüklenen dosyanın URL\'si:', fileUrl);
} catch (error) {
console.error('Doğrudan S3\'e yükleme hatası:', error);
}
}
});
createMultipartUpload, uploadPart ve completeMultipartUpload işlemlerini kullanarak daha karmaşık bir Presigned URL mekanizması oluşturabilirsiniz. Bu, çok büyük dosyaları doğrudan istemciden S3'e parçalar halinde yüklemenize olanak tanır.
Presigned URL'ler, NestJS uygulamanızın performansını ve ölçeklenebilirliğini önemli ölçüde artırırken, AWS kimlik bilgilerinizin güvenliğini koruyarak güvenli bir dosya yükleme mekanizması sunar. Bu yöntem, özellikle mobil uygulamalar veya yüksek trafikli web uygulamaları için en iyi pratiklerden biridir.
Paralel Yüklemeler ve Hata Yönetimi: Performansı Maksimuma Çıkarma Stratejileri
Verimli S3 dosya yüklemelerinin temel taşlarından biri de paralel yükleme yeteneğidir. İster tek bir büyük dosyayı parçalar halinde yüklerken, isterse birden fazla küçük dosyayı aynı anda S3'e gönderirken, paralellik performansı önemli ölçüde artırabilir. Ayrıca, ağ kesintileri veya S3 tarafındaki geçici sorunlar nedeniyle oluşabilecek hataları etkin bir şekilde yönetmek, uygulamanızın dayanıklılığını ve kullanıcı deneyimini doğrudan etkiler.
Birden Fazla Dosyayı Paralel Yükleme
Çok sayıda kullanıcının aynı anda birden fazla dosya yüklemesi gerektiği senaryolarda (örneğin bir fotoğraf galerisine toplu yükleme), her dosyayı sırayla yüklemek verimsiz olacaktır. JavaScript'in Promise tabanlı yapısı ve Promise.all gibi metodlar sayesinde, birden fazla S3 yüklemesini aynı anda başlatmak mümkündür. NestJS servisinizdeki uploadFile (veya uploadLargeFile) metodunuz bir Promise döndürdüğü sürece, bu kolayca yapılabilir:
// s3.service.ts (var olan metodları kullanırız)
// app.controller.ts - Birden fazla dosya yükleme endpoint'i
import { Controller, Post, UseInterceptors, UploadedFiles } from '@nestjs/common';
import { FilesInterceptor } from '@nestjs/platform-express'; // Birden fazla dosya için FilesInterceptor
import { S3Service } from './s3.service';
import { multerOptions } from './config/multer.config'; // Multer yapılandırmanız
@Controller('files')
export class AppController {
constructor(private readonly s3Service: S3Service) {}
@Post('upload-multiple')
@UseInterceptors(FilesInterceptor('files', 10, multerOptions)) // 'files' form alanının adı, max 10 dosya
async uploadMultipleFiles(@UploadedFiles() files: Array) {
if (!files || files.length === 0) {
throw new Error('Yüklenecek dosya bulunamadı.');
}
// Her dosya için S3 yüklemesini başlat ve Promise'leri topla
const uploadPromises = files.map(file => this.s3Service.uploadLargeFile(file)); // Veya uploadFile
try {
const uploadedUrls = await Promise.all(uploadPromises); // Tüm Promise'lerin tamamlanmasını bekle
return { message: ${uploadedUrls.length} dosya başarıyla yüklendi!, urls: uploadedUrls };
} catch (error) {
console.error('Toplu dosya yükleme hatası:', error);
throw new Error('Dosyalar yüklenirken bir hata oluştu.');
}
}
}
FilesInterceptor ile gelen tüm dosyalar için ayrı ayrı uploadLargeFile (veya uploadFile) çağrılır ve bu çağrılar bir dizi Promise olarak uploadPromises'a eklenir. Promise.all, tüm bu yüklemelerin paralel olarak tamamlanmasını bekler. Eğer bir yükleme başarısız olursa, Promise.all reddedilir ve toplu yükleme işlemi hata verir. Bu yaklaşım, NestJS sunucunuzun birden fazla dosyayı aynı anda işleyerek genel yükleme süresini ciddi şekilde kısaltmasını sağlar.
Büyük Dosyalarda Parçacıkların (Parts) Paralel Yüklenmesi
Daha önce bahsettiğimiz Upload sınıfı, büyük dosyaları parçalara bölerek bu parçaları otomatik olarak paralel yükler. queueSize ve partSize parametreleri bu paralelliği kontrol etmenizi sağlar. Doğru yapılandırıldığında, bu sınıf S3'ün sunduğu tam bant genişliğinden faydalanarak tek bir büyük dosyanın bile çok daha hızlı yüklenmesini sağlar. Örneğin, 1 GB'lık bir dosyayı 5 MB'lık parçalara böldüğünüzde 200 parça elde edersiniz. Bu 200 parçayı 4'erli gruplar halinde paralel yüklemek, sıralı yüklemeye kıyasla çok daha hızlı olacaktır.
Yükleme Kesintileri ve Devam Ettirme Mekanizmaları
Özellikle büyük dosyalar yüklenirken veya mobil ortamlarda ağ bağlantısı zayıf olduğunda yüklemeler kesintiye uğrayabilir. Multipart Upload, doğası gereği bu tür kesintilere karşı daha dayanıklıdır. Eğer bir parça yüklemesi başarısız olursa, sadece o parçayı tekrar göndermek yeterlidir. Tamamıyle baştan başlamak zorunda kalmazsınız. Ancak, bu mekanizmayı etkin bir şekilde kullanabilmek için istemci tarafında da bir "devam ettirme" (resumable upload) mantığına ihtiyacınız olabilir. İstemci, hangi parçaların başarıyla yüklendiğini takip ederek, kesinti sonrası sadece kalan parçaları göndermeye devam edebilir. Bu, genellikle bir ara depolama (örneğin yerel depolama) ve S3'ten tamamlanmış parçaların listesini sorgulama ile yönetilir. AWS SDK'nın Upload sınıfı bu süreci bir miktar otomatikleştirse de, tam bir devam ettirme yeteneği için istemci-sunucu arasında daha detaylı bir durum takibi gerekebilir.
Hata Tekrar Denemeleri (Retry Logic) ve Exponential Backoff
Geçici ağ sorunları, S3 API limitlerine takılma veya diğer beklenmedik durumlar yükleme hatalarına yol açabilir. Bu tür durumlarda, anında vazgeçmek yerine, belirli bir sayıda tekrar deneme yapmak uygulamanızın daha sağlam olmasını sağlar. Ancak, basit bir tekrar deneme döngüsü bazen durumu kötüleştirebilir (örneğin bir hizmet kesintisi sırasında S3'e yapılan istek selini artırmak). Bu nedenle, Exponential Backoff stratejisi kullanmak önemlidir. Bu stratejide, her tekrar deneme arasında beklenen süre, her başarısız denemede katlanarak artar. Bu, sistemin toparlanmasına zaman tanır ve sunuculara aşırı yük bindirmeyi önler.
Örnek bir retry mekanizması (kavramsal):
async function reliableUpload(s3Client: S3Client, params: any, maxRetries = 5) {
let retries = 0;
while (retries < maxRetries) {
try {
await s3Client.send(new PutObjectCommand(params));
return true; // Başarılı
} catch (error) {
console.warn(Yükleme başarısız oldu, tekrar deneniyor (${retries + 1}/${maxRetries}):, error.message);
retries++;
const delay = Math.pow(2, retries) * 1000 + Math.random() * 1000; // 2, 4, 8, 16 saniye + rastgele jitter
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error('Yükleme maksimum tekrar denemesi sonrası başarısız oldu.');
}
Bu mekanizmayı S3Service içindeki uploadFile veya uploadLargeFile metotlarınıza entegre ederek uygulamanızın dosya yükleme konusunda çok daha dayanıklı olmasını sağlayabilirsiniz.
Bu stratejiler, NestJS uygulamanızın dosya yükleme performansını ve güvenilirliğini önemli ölçüde artırarak, kullanıcılara kesintisiz ve hızlı bir deneyim sunmanıza yardımcı olacaktır.
Depolama ve Maliyet Optimizasyonu: S3 Yaşam Döngüsü ve Sınıflandırma
AWS S3, sadece dosya yükleme ve indirme hizmeti sunmakla kalmaz, aynı zamanda farklı depolama sınıfları ve yaşam döngüsü kuralları aracılığıyla maliyetleri optimize etme konusunda da esneklik sağlar. Verimli S3 kullanımı, sadece yükleme hızını değil, aynı zamanda depolama maliyetlerinizi de göz önünde bulundurmayı gerektirir. S3'ün sunduğu depolama sınıflarını ve yaşam döngüsü kurallarını doğru bir şekilde anlamak ve uygulamak, uzun vadede önemli tasarruflar sağlayabilir.
S3 Depolama Sınıfları Nelerdir ve Nasıl Seçilir?
S3, farklı erişim sıklığı ve performans ihtiyaçlarına göre optimize edilmiş çeşitli depolama sınıfları sunar. Her sınıfın farklı bir maliyet yapısı vardır:
- Standard (S3 Standard): Sık erişilen veriler için tasarlanmıştır. Düşük gecikme süresi ve yüksek verim sunar. En pahalı depolama sınıfıdır ancak en hızlı erişimi sağlar.
- Intelligent-Tiering (S3 Intelligent-Tiering): Veri erişim desenlerini otomatik olarak izler ve nesneleri en uygun depolama katmanına taşır. Erişimin değiştiği, bilinmeyen veya tahmin edilemeyen veri setleri için idealdir. Verileri sık erişim katmanından seyrek erişim katmanına veya tam tersine otomatik olarak taşır.
- Standard-Infrequent Access (S3 Standard-IA): Daha az sıklıkla erişilen ancak gerektiğinde hızlı erişim gerektiren veriler için tasarlanmıştır (örneğin, yedeklemeler, olağanüstü durum kurtarma dosyaları). Depolama maliyeti daha düşüktür ancak veri alımı (retrieval) maliyeti vardır.
- One Zone-Infrequent Access (S3 One Zone-IA): Standard-IA ile benzerdir ancak veriler tek bir AWS Erişilebilirlik Alanı'nda (Availability Zone) depolanır. Daha düşük maliyetlidir ancak bir bölgedeki olaylarda veri kaybı riski taşır.
- Glacier (S3 Glacier) ve Glacier Deep Archive (S3 Glacier Deep Archive): Arşivleme için tasarlanmıştır. Veri alım süreleri dakikalar veya saatler sürebilir. En düşük depolama maliyetini sunarlar ve uzun vadeli, nadiren erişilen veriler için uygundur (örneğin, yasal arşivler, uzun vadeli yedeklemeler).
NestJS uygulamanız S3'e dosya yüklerken, PutObjectCommand parametrelerinde StorageClass özelliğini belirterek bir depolama sınıfı atayabilirsiniz:
const params = {
Bucket: this.bucketName,
Key: uniqueFileName,
Body: file.buffer,
ContentType: file.mimetype,
ACL: 'public-read',
StorageClass: 'STANDARD_IA', // Örneğin, Standard-IA olarak belirleyelim
};
await this.s3Client.send(new PutObjectCommand(params));
Ancak, genellikle başlangıçta STANDARD sınıfını kullanmak ve daha sonra "Yaşam Döngüsü Kuralları" ile diğer sınıflara geçiş yapmak daha pratik bir yaklaşımdır.
Yaşam Döngüsü Kuralları (Lifecycle Rules) ile Otomatik Yönetim
S3 yaşam döngüsü kuralları, nesnelerinizin belirli bir süre sonra otomatik olarak farklı bir depolama sınıfına taşınmasını veya süresi dolduğunda silinmesini sağlar. Bu, manuel müdahaleye gerek kalmadan maliyetleri optimize etmenin güçlü bir yoludur. Örneğin, yeni yüklenen bir fotoğrafın ilk 30 gün boyunca STANDARD sınıfta kalmasını, ardından 60 gün boyunca STANDARD_IA sınıfına geçmesini ve son olarak 1 yıl sonra GLACIER'a arşivlenmesini sağlayabilirsiniz.
Yaşam döngüsü kuralları, AWS Yönetim Konsolu, AWS CLI veya SDK aracılığıyla bir S3 bucket'ına uygulanır. NestJS uygulamanız, S3'e dosya yüklerken bu kuralları doğrudan oluşturmaz veya değiştirmez; uygulamanız sadece dosyaları bucket'a yükler ve S3 tarafında tanımlanmış kurallar otomatik olarak devreye girer. Bu, uygulamanızın iş mantığını basitleştirir ve depolama yönetimini S3'ün kendi yeteneklerine bırakır.
Örnek bir yaşam döngüsü kuralı senaryosu:
- Kullanıcılar fotoğraf yükler (varsayılan
STANDARDsınıfı). - Fotoğraflar 30 gün boyunca sık erişime açık kalır.
- 30 gün sonra, kural otomatik olarak bu fotoğrafları
STANDARD_IAsınıfına taşır (daha düşük depolama maliyeti, yine de hızlı erişim). - 90 gün sonra, kural fotoğrafları
GLACIERsınıfına taşır (arşivleme, en düşük maliyet, daha yavaş erişim). - 5 yıl sonra, kural fotoğrafları kalıcı olarak siler.
Bu şekilde, verilerin "sıcaklığına" (ne kadar sık erişildiğine) göre dinamik olarak maliyet optimizasyonu yapabilirsiniz. Özellikle log dosyaları, eski yedekler veya nadiren başvurulan medya içerikleri için yaşam döngüsü kuralları vazgeçilmezdir.
Bu optimizasyonlar, NestJS uygulamanızın dosya yükleme mekanizmasının sadece hızlı ve güvenilir olmasını sağlamakla kalmaz, aynı zamanda bulut altyapısı maliyetlerinizi de kontrol altında tutarak uzun vadeli sürdürülebilirliğini garantiler.
NestJS S3 Yüklemelerinde Performans İpuçları ve En İyi Uygulamalar Nelerdir?
NestJS ile AWS S3 dosya yüklemelerini sadece çalışır hale getirmek yeterli değildir; gerçekten verimli, hızlı ve güvenli bir sistem kurmak için bazı ileri düzey ipuçları ve en iyi uygulamaları takip etmek gerekir. Bu bölüm, sisteminizi maksimum performansa ulaştırmak ve olası sorunların önüne geçmek için kritik stratejileri ele almaktadır.
Bölge Seçimi (Region) ve Gecikme Süresi (Latency)
S3 bucket'ınızı oluştururken seçtiğiniz AWS bölgesi, uygulamanızın ve kullanıcılarınızın konumuna göre önemli bir performans faktörüdür. Kullanıcılarınızın çoğunluğunun coğrafi olarak yakın olduğu bir bölge seçmek, S3'e yapılan isteklerin gecikme süresini (latency) minimize eder. Daha düşük gecikme süresi, daha hızlı yükleme ve indirme deneyimi anlamına gelir. Örneğin, Türkiye'deki kullanıcıları hedefliyorsanız, Frankfurt (eu-central-1) gibi yakın bir Avrupa bölgesi genellikle iyi bir seçimdir. Global bir kullanıcı kitleniz varsa, birden fazla bölgede S3 bucket'ları bulundurmayı veya AWS Global Accelerator gibi hizmetleri değerlendirmeyi düşünebilirsiniz.
Kullanıcı Konumuna En Yakın CDN (CloudFront) Kullanımı
Dosyalar S3'e yüklendikten sonra, özellikle herkese açık veya sık erişilen dosyalar için bir İçerik Dağıtım Ağı (CDN) kullanmak performansı katlar. AWS CloudFront, S3 ile derinlemesine entegre çalışır. CloudFront, dosyalarınızın kopyalarını dünyanın dört bir yanındaki "edge location" (uç nokta) sunucularında önbelleğe alır. Bir kullanıcı bir dosyaya eriştiğinde, dosya ona coğrafi olarak en yakın uç noktadan sunulur. Bu, gecikmeyi önemli ölçüde azaltır ve yükleme sonrası indirme hızlarını artırır. Ayrıca, S3'ten doğrudan okuma trafiğini azaltarak maliyetleri de düşürebilir. NestJS uygulamanız S3'e yükledikten sonra dönen URL'leri CloudFront domain'i ile değiştirerek bu entegrasyonu sağlayabilirsiniz.
Bellek ve CPU Kaynaklarını Optimize Etme
NestJS sunucunuz, dosya yükleme sürecinde bellek ve CPU kaynaklarını kullanır. Özellikle buffer tabanlı yüklemelerde veya büyük dosyaları işlerken bu tüketim artabilir. Optimize edilmiş bir uygulama için:
- Stream tabanlı yüklemeleri tercih edin: Mümkün olduğunca dosyaları doğrudan S3'e akış halinde gönderin, sunucu belleğinde tutmaktan kaçının. Bu, büyük dosyalar için kritiktir.
- Multer limitlerini belirleyin: Bellek veya disk kullanımını sınırlamak için
multeryapılandırmanızdafileSizevefilesgibi limitleri doğru ayarlayın. - Arka plan işlemleri: Ağır dosya işleme (resim yeniden boyutlandırma, video dönüştürme) gerekiyorsa, bunu NestJS uygulamanızın ana akışından ayırın. Bu tür görevler için SQS, Lambda ve S3 olay tetikleyicileri gibi AWS hizmetlerini kullanarak sunucusuz bir işleme hattı oluşturun. Dosya S3'e yüklendiğinde bir S3 olayı tetiklenir, bu olay bir Lambda fonksiyonunu veya SQS kuyruğunu çalıştırabilir.
Güvenlik: IAM Rolleri, Bucket Politikaları ve Şifreleme
Performans kadar güvenlik de hayati öneme sahiptir:
- Minimum Yetki İlkesi (Principle of Least Privilege): NestJS uygulamanızın AWS kimlik bilgileri (IAM kullanıcı veya rolü), S3 üzerinde sadece ihtiyacı olan işlemleri yapmasına izin veren yetkilere sahip olmalıdır (örneğin, sadece belirli bir bucket'a
PutObjectizni). Asla tam yönetici izni vermeyin. - Bucket Politikaları: S3 bucket'larınıza erişimi kontrol etmek için bucket politikalarını kullanın. Örneğin, belirli IP adreslerinden veya belirli IAM rollerinden gelen isteklere izin verin.
- Nesne ACL'leri: Dosyaların herkese açık olup olmayacağını belirleyen ACL'leri (Access Control List) dikkatli kullanın. Varsayılan olarak özel tutmak ve sadece gerektiğinde Presigned URL'lerle geçici erişim sağlamak daha güvenlidir.
- Şifreleme: Hassas verileri S3'te şifrelemek için Sunucu Tarafı Şifreleme'yi (SSE-S3, SSE-KMS veya SSE-C) kullanın. NestJS uygulamanız yükleme yaparken bu seçenekleri belirtebilirsiniz.
Monitoring ve Logging (CloudWatch)
S3 yükleme işlemlerinizin performansını ve güvenilirliğini izlemek için AWS CloudWatch'u kullanın. S3, bucket seviyesinde birçok metrik (istek sayısı, hata sayısı, aktarılan veri) sunar. Ayrıca, NestJS uygulamanızdaki S3 yükleme işlemlerinin loglarını (başarılı/başarısız yüklemeler, süreler) CloudWatch Logs'a göndererek merkezi bir izleme sistemi kurabilirsiniz. Bu sayede olası darboğazları veya hata kaynaklarını hızla tespit edip müdahale edebilirsiniz.
Mobil Uyumlu HTML ve Kullanıcı Deneyimi
Mobil cihazlardan yapılan dosya yüklemeleri için kullanıcı deneyimi büyük önem taşır. Yüksek çözünürlüklü ekranlar için tasarlanmış, duyarlı bir kullanıcı arayüzü sunmak gerekir. CSS media query'leri, farklı ekran boyutlarına ve cihazlara göre arayüzün otomatik olarak uyum sağlamasına olanak tanır. Örneğin, bir dosya yükleme formunun genişliği, düğmelerin boyutu veya ilerleme çubuğunun görünümü mobil cihazlarda daha okunaklı ve kullanılabilir olacak şekilde ayarlanabilir. Bu, doğrudan NestJS backend kodunu etkilemese de, dosya yükleme deneyiminin tamamlayıcı bir parçasıdır ve frontend geliştiriciler için birincil bir endişe kaynağıdır. Hızlı yükleme hızları, şık bir ilerleme göstergesi ve hatalara karşı dayanıklı bir sistem, mobil kullanıcılar için hayati öneme sahiptir.
/* Örnek bir mobil uyumlu CSS medya sorgusu */
@media (max-width: 768px) {
.upload-container {
flex-direction: column;
padding: 15px;
}
.upload-button {
width: 100%;
margin-top: 10px;
}
.progress-bar {
height: 15px;
}
}
Bu ipuçlarını uygulayarak, NestJS ve AWS S3 entegrasyonunuzu sadece işlevsel kılmakla kalmayacak, aynı zamanda yüksek performanslı, güvenli ve maliyet-etkin bir çözüm haline getireceksiniz. Bu, uygulamanızın ölçeklenebilirliğini artıracak ve kullanıcılara üstün bir deneyim sunacaktır.
Sonuç: Verimli S3 Dosya Yüklemeleriyle Uygulamalarınızı Geleceğe Taşıyın
NestJS ile AWS S3 entegrasyonu, modern web ve mobil uygulamalar için dosya depolama ve yönetimi konusunda güçlü ve ölçeklenebilir bir temel sunar. Bu makale boyunca, küçük ve orta boyutlu dosyalardan başlayarak, büyük dosyaların stream tabanlı ve multipart upload yöntemleriyle nasıl daha verimli yüklenebileceğine, Presigned URL'ler aracılığıyla sunucu yükünün nasıl azaltılabileceğine ve paralel yüklemelerle hata yönetiminin önemine değindik. Ayrıca, S3 depolama sınıfları ve yaşam döngüsü kurallarıyla maliyet optimizasyonunu, bölge seçimi, CDN entegrasyonu ve güvenlik gibi performans ipuçlarını da ele aldık.
Unutmamak gerekir ki, her uygulamanın ihtiyaçları farklıdır ve "tek beden herkese uyar" bir çözüm bulunmamaktadır. Ancak burada paylaşılan stratejiler ve en iyi uygulamalar, kendi NestJS projenizin özel gereksinimlerine göre uyarlayabileceğiniz sağlam bir başlangıç noktası sunmaktadır. Doğru yaklaşım, hem geliştirme sürecinizi kolaylaştıracak hem de son kullanıcılarınıza daha hızlı, daha güvenilir ve daha maliyet-etkin bir deneyim sunacaktır. Verimli S3 dosya yüklemeleri, sadece bir teknik gereklilik değil, aynı zamanda uygulamanızın başarısı için kritik bir rekabet avantajıdır. Bu bilgilerle donanarak, NestJS tabanlı uygulamalarınızı geleceğe taşıyacak ve dijital dünyadaki yerinizi sağlamlaştıracaksınız.
Sıkça Sorulan Sorular (SSS)
İşte NestJS ve S3 dosya yüklemeleriyle ilgili sıkça karşılaşılan bazı sorular ve yanıtları:
-
S: NestJS uygulamamda neden doğrudan S3'e yükleme yapmak yerine sunucu üzerinden yükleme yapıyorum?
C: Doğrudan S3'e yükleme (Presigned URL'ler aracılığıyla) genellikle daha iyi bir performans ve ölçeklenebilirlik sağlar çünkü dosya sunucu üzerinden geçmez. Ancak, bazı durumlarda sunucu üzerinden yükleme tercih edilebilir:- Dosya üzerinde sunucuda ek işleme (örneğin virüs taraması, format dönüştürme) yapılması gerekiyorsa.
- Uygulamanızın güvenlik modeli Presigned URL'leri kullanmaya uygun değilse.
- Küçük dosyalar için performans farkı ihmal edilebilir düzeyde olduğundan basitlik adına sunucu üzerinden yükleme tercih edilebilir.
-
S: Büyük dosyaları yüklerken NestJS sunucumun bellek tüketimini nasıl minimize edebilirim?
C: Büyük dosyalar için stream tabanlı yüklemeleri tercih edin. Multer'ımemoryStorageyerinediskStorageile yapılandırın veyaUploadsınıfı gibi AWS SDK'nın akış odaklı özelliklerini kullanarak dosyayı doğrudan S3'e akış halinde gönderin. Bu, dosyanın tamamının bellekte tutulmasını engeller. -
S: Yüklediğim dosyaların S3'te herkese açık olmasını nasıl sağlarım? Güvenlik riskleri var mı?
C:PutObjectCommandparametrelerindeACL: 'public-read'belirterek dosyaları herkese açık yapabilirsiniz. Ancak, bu her zaman önerilen bir yöntem değildir. Herkese açık dosyalar kötü niyetli erişim riskini artırır. Güvenlik için, Presigned URL'ler kullanarak geçici erişim sağlamayı veya CloudFront gibi bir CDN arkasından erişim kontrolünü yönetmeyi düşünün. Ayrıca, S3 bucket politikalarınızla genel erişimi kısıtlayın ve sadece belirli durumlarda belirli nesnelere erişim sağlayın. -
S: Yükleme sırasında ilerleme durumunu (progress) istemciye nasıl bildirebilirim?
C: AWS SDK'nınUploadsınıfı,httpUploadProgressolayı aracılığıyla yükleme ilerlemesi hakkında bilgi sağlar. Bu olayı dinleyerek (parallelUploads.on('httpUploadProgress', ...)) yüklenen ve toplam byte miktarını alabilirsiniz. Bu bilgiyi daha sonra WebSocket veya Server-Sent Events (SSE) gibi teknolojilerle istemciye ileterek bir ilerleme çubuğu gösterebilirsiniz. Presigned URL ile doğrudan S3'e yükleme yaparken, istemci tarafındaki HTTP isteği (örneğinXMLHttpRequestveya özel Axios konfigürasyonları) kendi ilerleme olaylarını sağlayabilir.
