Dosya yükleme etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Dosya yükleme etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

23 Eylül 2025 Salı

Next.js 14’te Server Actions ile Güvenli Form ve Dosya Yükleme: Adım Adım Rehber

Giriş

Next.js 14 ile birlikte hayatımıza giren Server Actions, form işlemleri ve veri mutasyonlarını API katmanı yazmadan, doğrudan sunucuda çalıştırılabilir fonksiyonlarla yönetmemizi sağlıyor. Bu yaklaşım hem güvenliği artırıyor hem de geliştirici deneyimini iyileştiriyor. Bu yazıda, App Router mimarisi altında Server Actions kullanarak güvenli form işleme ve dosya yükleme senaryosunu adım adım ele alacağız. Ayrıca performans, SEO ve güvenlik tarafındaki püf noktalarına da değineceğiz.

Önkoşullar ve Kurulum

Başlamadan önce Node.js 18+ ve Next.js 14 ortamınız hazır olmalı. Projeyi TypeScript ile başlatmanızı öneririm; tip güvenliği hem sunucu eylemlerinde hem de form verisi doğrulamada büyük kolaylık sağlar. App Router (app/ dizini) kullanıyorsanız, sayfalarınız React Server Components olarak varsayılan şekilde sunulur; bu sayede istemciye daha az JavaScript gönderilir ve SEO performansınız artar.

Server Actions Mantığı

Server Actions, bir fonksiyonun başına "use server" yönergesi eklenerek sunucuda çalıştırılmasını sağlar. Bu fonksiyonları doğrudan formun action props’una bağlayabilir ve formData alabilirsiniz. Ek bir API route yazmanız gerekmez. İş mantığı sunucuda kaldığı için token, bağlantı string’i ve gizli anahtarlar istemciye sızmaz. İşlem sonrası önbelleği tazelemek için revalidatePath() veya revalidateTag() çağırabilirsiniz.

Form Doğrulama Stratejisi

Doğrulama iki katmanda yapılmalı: istemci tarafında kullanıcı deneyimini iyileştiren anlık kontroller (örneğin e-posta formatı), sunucu tarafında ise kaynak güvenliği sağlayan kesin doğrulamalar. Server Actions içinde zod gibi bir şema doğrulama kütüphanesi kullanarak tip güvenli ve anlaşılır hata mesajları üretin. Hataları action’dan geriye döndürüp formda kullanıcıya göstermek, klasik API isteklerine göre daha yalın bir akış sağlar.

Dosya Yükleme: Route Handler mı, Server Action mı?

Basit senaryolarda formunuzdaki dosya alanını Server Action içinde formData.get("file") ile alabilirsiniz. Ancak büyük dosyalar, virüs taraması veya üçüncü taraf depolama (S3, R2 vb.) gerekiyorsa Route Handlers (app/route.ts) tercih edin. Bu sayede streaming ile bellek kullanımını kontrol edebilir, sınırları (limits) ve doğrulamayı daha esnek yönetebilirsiniz. Platformunuza göre runtime seçimi önemlidir: Node özelliklerine ihtiyaç varsa export const runtime = "nodejs" kullanın; global edge ağı üzerinde düşük gecikme istiyorsanız "edge" seçeneğini değerlendirin.

Adım Adım Senaryo: Profil Formu + Avatar Yükleme

1) Formu Tasarlayın: İsim, e-posta, kısa bio ve avatar dosya alanı ekleyin. Geriye dönüt için alan bazlı hata mesajları ve formun gönderim durumunu göstermek üzere bir yükleniyor göstergesi ekleyin.

2) Server Action Yazın: "use server" ile başlayan saveProfile fonksiyonu, formData içinden girişleri okur. zod ile isim ve e-posta zorunlu, bio uzunluğu sınırlı olacak şekilde doğrulayın. Doğrulama hatalarını sade bir nesne olarak geri döndürün.

3) Avatar İçin Doğrulama: MIME türü (image/jpeg, image/png), dosya boyutu (ör. 2 MB sınır), ve görüntü boyutları (ör. 1024x1024 üstü reddedilsin) kontrol edin. Şüpheli içerik için içerik taraması gerekiyorsa, asenkron bir kuyruk (örn. SQS, Pub/Sub) veya webhook tabanlı işleme düşünebilirsiniz.

4) Depolama Stratejisi: Büyük dosyaları doğrudan Server Action üzerinden aktarmak yerine, istemcide önceden imzalı URL (pre-signed URL) alıp doğrudan depolamaya yüklemek daha verimlidir. Bu yaklaşım, sunucu trafiğini azaltır ve edge bölgelerinde daha hızlıdır. Ardından Server Action sadece meta veriyi (dosya URL’si) veritabanına kaydeder.

5) Önbellek ve Yeniden Doğrulama: Profil sayfanız statikse bile güncelleme sonrası revalidatePath("/profil") ile görünümü anında tazeleyin. Eğer profil verilerini cache tag ile etiketlediyseniz, revalidateTag("profil") çağrısı da etkili olacaktır.

6) UX İyileştirmeleri: Progressive enhancement mantığıyla, JavaScript kapalıyken dahi form çalışmalı; JS açıkken ise iyileştirmeler devreye girmeli. useFormStatus ile buton durumunu yönetin, belirli alanlar için optimistic UI uygulayın.

Güvenlik İpuçları

CSRF: Server Actions form gönderiminde varsayılan olarak korumalı bir yol sağlar; yine de hassas işlemlerde ek kontrol (ör. origin doğrulama) uygulayın. Rate Limiting: Brute-force girişimleri için IP veya token bazlı sınırlama ekleyin. Dosya Güvenliği: İçerik türü ve boyut kontrolü zorunlu; antivirüs taraması ve izole geçici depolama ile zinciri güçlendirin. Gizli Anahtarlar: Tüm sırları process.env üzerinden sunucuda okuyun; istemciye sızdırmayın.

Performans ve SEO

App Router ile sayfalarınız server-rendered çalıştığı için ilk yükleme süresi ve SEO performansı güçlüdür. Server Actions, veri mutasyonunu aynı kökten ele aldığından fazladan JSON döndürme ve istemci durum yönetimi yükünü azaltır. Yalnızca değişmesi gereken segmentleri yeniden doğrulamak, gereksiz yeniden oluşturma maliyetini düşürür. Görsel ve statik varlıklar için HTTP cache başlıklarını doğru ayarlayın, kritik CSS’i minimal tutun.

Hata Ayıklama ve Test

Geliştirme sırasında action’larınızın giriş ve çıkışlarını ayrıntılı loglayın; hassas verileri loglardan uzak tutun. Birim testlerde, doğrulama şemalarını ve yan etkisiz iş mantığını izole ederek test edin. Uçtan uca testlerde (Playwright) gerçekçi form doldurma ve dosya yükleme akışlarını, hata durumlarını ve erişilebilirlik kontrollerini (klavye navigasyonu, ARIA etiketleri) kapsayın.

Sonuç

Next.js 14’te Server Actions, form ve dosya yükleme gibi günlük iş akışlarını basitleştirirken güvenlik ve performans avantajı da sağlar. Doğrulama, depolama ve önbellek stratejilerini doğru kurguladığınızda daha az kodla daha ölçeklenebilir bir çözüm elde edersiniz. Küçük bir profil formundan kurumsal bir içerik yönetim sistemine kadar aynı ilkelere dayanarak karmaşık senaryoları dahi güvenle kurgulayabilirsiniz.

12 Eylül 2025 Cuma

Next.js 14’te Server Actions ile Güvenli Form ve Dosya Yükleme: Adım Adım Rehber

Next.js 14 ile birlikte gelen Server Actions, form gönderimlerini sunucu tarafında güvenle işlemek ve istemci kodunu sadeleştirmek için güçlü bir seçenek sunar. Bu rehberde, e-posta alanı içeren basit bir formu ve güvenli dosya yükleme akışını, Zod ile doğrulama yaparak adım adım kuracağız. Hedefimiz, gereksiz API katmanları oluşturmadan, tek bir action ile temiz ve ölçeklenebilir bir çözüm elde etmek.

Server Actions yaklaşımı; XHR/fetch kodlarını azaltır, React Server Components ile uyumlu çalışır ve SSR/ISR stratejilerine zarar vermeden form iş akışlarını basitleştirir. Dosya işlemlerinde ise tür ve boyut kontrolüyle güvenlik yüzeyini daraltır. Vercel gibi platformlarda çalışırken /tmp gibi geçici dizinlerin kullanımı mümkündür; kalıcı depolama için S3 benzeri servisler önerilir.

Gereksinimler

- Node.js 18+ ve Next.js 14+

- Paket yöneticisi (pnpm, npm veya yarn)

- (İsteğe bağlı) Zod ile şema tabanlı doğrulama

Kurulum ve Hazırlık

Yeni bir proje başlatalım:

npx create-next-app@latest next14-server-actions
cd next14-server-actions
pnpm add zod

Server Actions Next.js 14’te varsayılan olarak desteklenir. Projenizde gerekirse aşağıdaki gibi bir yapılandırma ile istek boyutunu kontrol edebilirsiniz (opsiyonel):

// next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    serverActions: {
      bodySizeLimit: '6mb' // FormData sınırı (opsiyonel)
    }
  }
};
export default nextConfig;

Server Action: Doğrulama ve Yükleme

Aşağıdaki action, e-postayı Zod ile doğrular, dosya türünü ve boyutunu kontrol eder, ardından dosyayı bir hedef dizine yazar. Geliştirme ve Vercel üzerinde test için varsayılan olarak /tmp kullanılabilir.

// app/actions.ts
'use server';

import { z } from 'zod';
import { writeFile } from 'fs/promises';
import path from 'path';
import crypto from 'crypto';

const schema = z.object({
  email: z.string().email()
});

// Node.js API'larına ihtiyacımız olduğundan runtime'ı Node olarak zorlayalım (opsiyonel).
export const runtime = 'nodejs';

export async function uploadFile(formData: FormData) {
  const email = String(formData.get('email') || '');
  const file = formData.get('file');

  const parsed = schema.safeParse({ email });
  if (!parsed.success) {
    return { ok: false, error: 'Geçersiz e-posta adresi.' };
  }

  if (!(file instanceof File)) {
    return { ok: false, error: 'Dosya bulunamadı.' };
  }

  const allowed = ['image/png', 'image/jpeg', 'application/pdf'];
  if (!allowed.includes(file.type)) {
    return { ok: false, error: 'İzin verilmeyen dosya türü.' };
  }

  const MAX = 5 * 1024 * 1024; // 5MB
  if (file.size > MAX) {
    return { ok: false, error: 'Dosya boyutu 5MB sınırını aşıyor.' };
  }

  const arrayBuffer = await file.arrayBuffer();
  const buffer = Buffer.from(arrayBuffer);

  const filename =
    crypto.randomBytes(8).toString('hex') + '-' + (file.name || 'upload');
  const destDir = process.env.UPLOAD_DIR || '/tmp';
  const destPath = path.join(destDir, filename);

  await writeFile(destPath, buffer);

  return { ok: true, path: destPath };
}

Form Bileşeni ve Kullanım

Formun action özelliğine doğrudan server action’ı vererek kolayca bağlayabiliriz. Bu sayede client tarafında ekstra fetch mantığına gerek kalmaz.

// app/page.tsx
import { uploadFile } from './actions';

export default function Page() {
  return (
    <main style={{ maxWidth: 560, margin: '40px auto', fontFamily: 'sans-serif' }}>
      <h1>Dosya Yükleme Formu</h1>
      <form action={uploadFile}>
        <label>E-posta</label>
        <input type="email" name="email" required placeholder="[email protected]" />

        <label style={{ display: 'block', marginTop: 12 }}>Dosya (PNG/JPEG/PDF)</label>
        <input type="file" name="file" accept="image/png,image/jpeg,application/pdf" required />

        <button type="submit" style={{ marginTop: 16 }}>Gönder</button>
      </form>
      <p style={{ fontSize: 12, color: '#666', marginTop: 12 }}>
        Not: Demo amaçlı yüklemeler geçici dizine kaydedilir.
      </p>
    </main>
  );
}

İsterseniz kullanıcı deneyimini iyileştirmek için Client bileşeninde submit durumunu gösterebilir, form sonucunu Server Action’dan dönen nesneye göre ekrana yazdırabilirsiniz. Daha gelişmiş bir deneyim için useFormStatus ve useFormState yardımcılarını değerlendirebilirsiniz.

Güvenlik ve En İyi Uygulamalar

- Dosya türlerini beyaz listeyle sınırlandırın (PNG, JPEG, PDF gibi). Gerekirse MIME kontrolüne ek olarak sihirli bayt (magic bytes) kontrolü uygulayın.

- Boyut limiti belirleyin ve Next.js yapılandırmasında body limiti ile eşleştirin.

- Kalıcı depolama için S3 veya benzeri bir objeler deposu kullanın; dosya adlarını çakışmaları önlemek için hashleyin.

- İşlem süresi ve ortam kısıtları için Node.js runtime tercih edin; kenar (Edge) iş yüklerinde dosya manipülasyonu yerine imzalı URL yaklaşımı kullanın.

Çalıştırma ve Dağıtım

Geliştirme ortamında başlatmak için:

pnpm dev

Vercel’e dağıtırken ek bir API katmanına ihtiyaç duymadan aynı kod çalışır. Yalnızca kalıcı depolama kullanacaksanız ilgili servis kimlik bilgilerini çevresel değişkenlerle (ör. S3_ACCESS_KEY, S3_BUCKET) eklemeyi unutmayın.

Sonuç olarak, Next.js 14’te Server Actions ile güvenli ve performanslı bir dosya yükleme akışını, sade bir mimariyle hayata geçirebilirsiniz. Zod tabanlı doğrulama, sınırlı dosya türleri ve boyut kontrolleri ile riskleri minimize ederken, kullanıcıya yalın bir deneyim sunarsınız.