Gelen istekleri yakalamak ve değiştirmek için güçlü bir özellik olan Next.js middleware'i keşfedin. Pratik örneklerle kimlik doğrulama, yetkilendirme, yönlendirme ve A/B testlerini nasıl uygulayacağınızı öğrenin.
Next.js Middleware: Dinamik Uygulamalar için İstek Yakalamada Uzmanlaşma
Next.js middleware, gelen istekleri rotalarınıza ulaşmadan önce yakalamak ve değiştirmek için esnek ve güçlü bir yol sunar. Bu yetenek, kimlik doğrulama ve yetkilendirmeden yönlendirme ve A/B testine kadar geniş bir yelpazede özellikleri uygulamanıza olanak tanırken aynı zamanda performansı optimize eder. Bu kapsamlı kılavuz, Next.js middleware'in temel kavramlarını anlatacak ve onu nasıl etkili bir şekilde kullanacağınızı gösterecektir.
Next.js Middleware Nedir?
Next.js'teki middleware, bir istek tamamlanmadan önce çalışan bir fonksiyondur. Size şunları yapma olanağı sağlar:
- İstekleri yakalama: Gelen isteğin başlıklarını, çerezlerini ve URL'sini inceleme.
- İstekleri değiştirme: Belirli kriterlere göre URL'leri yeniden yazma, başlıkları ayarlama veya kullanıcıları yönlendirme.
- Kod çalıştırma: Bir sayfa render edilmeden önce sunucu tarafı mantığı çalıştırma.
Middleware fonksiyonları, projenizin kök dizinindeki middleware.ts
(veya middleware.js
) dosyasında tanımlanır. Uygulamanızdaki her rota için veya yapılandırılabilir eşleştiricilere (matchers) dayalı olarak belirli rotalar için yürütülürler.
Temel Kavramlar ve Avantajlar
Request (İstek) Nesnesi
request
nesnesi, gelen istekle ilgili bilgilere erişim sağlar, bunlar arasında:
request.url
: İsteğin tam URL'si.request.method
: HTTP metodu (ör. GET, POST).request.headers
: İstek başlıklarını içeren bir nesne.request.cookies
: İstek çerezlerini temsil eden bir nesne.request.geo
: Mevcutsa, istekle ilişkili coğrafi konum verilerini sağlar.
Response (Yanıt) Nesnesi
Middleware fonksiyonları, isteğin sonucunu kontrol etmek için bir Response
nesnesi döndürür. Aşağıdaki yanıtları kullanabilirsiniz:
NextResponse.next()
: İsteğin normal şekilde işlenmesine devam ederek hedeflenen rotaya ulaşmasını sağlar.NextResponse.redirect(url)
: Kullanıcıyı farklı bir URL'ye yönlendirir.NextResponse.rewrite(url)
: İstek URL'sini yeniden yazar, bir yönlendirme olmadan etkili bir şekilde farklı bir sayfa sunar. URL tarayıcıda aynı kalır.- Özel bir
Response
nesnesi döndürme: Hata sayfası veya belirli bir JSON yanıtı gibi özel içerik sunmanıza olanak tanır.
Eşleştiriciler (Matchers)
Eşleştiriciler, middleware'inizin hangi rotalara uygulanması gerektiğini belirtmenize olanak tanır. Düzenli ifadeler veya yol desenleri kullanarak eşleştiriciler tanımlayabilirsiniz. Bu, middleware'inizin yalnızca gerektiğinde çalışmasını sağlayarak performansı artırır ve ek yükü azaltır.
Edge Runtime
Next.js middleware, kullanıcılarınıza yakın bir konumda dağıtılabilen hafif bir JavaScript çalışma zamanı ortamı olan Edge Runtime üzerinde çalışır. Bu yakınlık, gecikmeyi en aza indirir ve uygulamanızın genel performansını, özellikle küresel olarak dağıtılmış kullanıcılar için iyileştirir. Edge Runtime, Vercel'in Edge Network'ünde ve diğer uyumlu platformlarda mevcuttur. Edge Runtime'ın bazı sınırlamaları vardır, özellikle de Node.js API'lerinin kullanımı.
Pratik Örnekler: Middleware Özelliklerini Uygulama
1. Kimlik Doğrulama (Authentication)
Kimlik doğrulama middleware'i, kullanıcıların giriş yapmasını gerektiren rotaları korumak için kullanılabilir. İşte çerezleri kullanarak kimlik doğrulamanın nasıl uygulanacağına dair bir örnek:
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth_token');
if (!token) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*'],
}
Bu middleware, bir auth_token
çerezinin varlığını kontrol eder. Çerez bulunmazsa, kullanıcı /login
sayfasına yönlendirilir. config.matcher
, bu middleware'in yalnızca /dashboard
altındaki rotalar için çalışması gerektiğini belirtir.
Küresel Perspektif: Farklı bölgelerden gelen kullanıcılara hizmet vermek için kimlik doğrulama mantığını çeşitli kimlik doğrulama yöntemlerini (ör. OAuth, JWT) destekleyecek ve farklı kimlik sağlayıcılarla (ör. Google, Facebook, Azure AD) entegre olacak şekilde uyarlayın.
2. Yetkilendirme (Authorization)
Yetkilendirme middleware'i, kullanıcı rollerine veya izinlerine göre kaynaklara erişimi kontrol etmek için kullanılabilir. Örneğin, yalnızca belirli kullanıcıların erişebileceği bir yönetici panonuz olabilir.
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export async function middleware(request: NextRequest) {
const token = request.cookies.get('auth_token');
if (!token) {
return NextResponse.redirect(new URL('/login', request.url))
}
// Örnek: Bir API'den kullanıcı rollerini al (kendi asıl mantığınızla değiştirin)
const userResponse = await fetch('https://api.example.com/userinfo', {
headers: {
Authorization: `Bearer ${token}`,
},
});
const userData = await userResponse.json();
if (userData.role !== 'admin') {
return NextResponse.redirect(new URL('/unauthorized', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/admin/:path*'],
}
Bu middleware, kullanıcının rolünü alır ve admin
rolüne sahip olup olmadıklarını kontrol eder. Değilse, /unauthorized
sayfasına yönlendirilirler. Bu örnek, bir yer tutucu API uç noktası kullanır. `https://api.example.com/userinfo` adresini kendi gerçek kimlik doğrulama sunucusu uç noktanızla değiştirin.
Küresel Perspektif: Kullanıcı verilerini işlerken veri gizliliği düzenlemelerine (ör. GDPR, CCPA) dikkat edin. Hassas bilgileri korumak ve yerel yasalara uyumu sağlamak için uygun güvenlik önlemlerini uygulayın.
3. Yönlendirme (Redirection)
Yönlendirme middleware'i, kullanıcıları konumlarına, dillerine veya diğer kriterlere göre yönlendirmek için kullanılabilir. Örneğin, kullanıcıları IP adreslerine göre web sitenizin yerelleştirilmiş bir sürümüne yönlendirebilirsiniz.
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const country = request.geo?.country || 'US'; // Coğrafi konum başarısız olursa varsayılan olarak ABD
if (country === 'DE') {
return NextResponse.redirect(new URL('/de', request.url))
}
if (country === 'FR') {
return NextResponse.redirect(new URL('/fr', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/'],
}
Bu middleware, kullanıcının ülkesini IP adresine göre kontrol eder ve onları web sitesinin uygun yerelleştirilmiş sürümüne (Almanya için /de
, Fransa için /fr
) yönlendirir. Coğrafi konum başarısız olursa, varsayılan olarak ABD sürümüne yönlendirilir. Bunun, geo özelliğinin mevcut olmasına (örneğin, Vercel'de dağıtıldığında) dayandığını unutmayın.
Küresel Perspektif: Web sitenizin birden fazla dili ve para birimini desteklediğinden emin olun. Kullanıcılara tercih ettikleri dili veya bölgeyi manuel olarak seçme seçeneği sunun. Her yerel ayar için uygun tarih ve saat biçimlerini kullanın.
4. A/B Testi
Middleware, kullanıcıları bir sayfanın farklı varyantlarına rastgele atayarak ve davranışlarını izleyerek A/B testi uygulamak için kullanılabilir. İşte basitleştirilmiş bir örnek:
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
function getRandomVariant() {
return Math.random() < 0.5 ? 'A' : 'B';
}
export function middleware(request: NextRequest) {
let variant = request.cookies.get('variant')?.value;
if (!variant) {
variant = getRandomVariant();
const response = NextResponse.next();
response.cookies.set('variant', variant);
return response;
}
if (variant === 'B') {
return NextResponse.rewrite(new URL('/variant-b', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/'],
}
Bu middleware, kullanıcıları 'A' veya 'B' varyantına atar. Bir kullanıcının zaten bir variant
çerezi yoksa, rastgele bir tane atanır ve ayarlanır. 'B' varyantına atanan kullanıcılar /variant-b
sayfasına yeniden yazılır. Daha sonra hangi varyantın daha etkili olduğunu belirlemek için her varyantın performansını izlersiniz.
Küresel Perspektif: A/B testleri tasarlarken kültürel farklılıkları göz önünde bulundurun. Bir bölgede iyi çalışan bir şey, başka bir bölgedeki kullanıcılarla aynı etkiyi yaratmayabilir. A/B test platformunuzun farklı bölgelerdeki gizlilik düzenlemeleriyle uyumlu olduğundan emin olun.
5. Özellik Bayrakları (Feature Flags)
Özellik bayrakları, yeni kod dağıtmadan uygulamanızdaki özellikleri etkinleştirmenize veya devre dışı bırakmanıza olanak tanır. Middleware, bir kullanıcının kullanıcı kimliğine, konumuna veya diğer kriterlere göre belirli bir özelliğe erişip erişemeyeceğini belirlemek için kullanılabilir.
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export async function middleware(request: NextRequest) {
// Örnek: Bir API'den özellik bayraklarını al
const featureFlagsResponse = await fetch('https://api.example.com/featureflags', {
headers: {
'X-User-Id': 'user123',
},
});
const featureFlags = await featureFlagsResponse.json();
if (featureFlags.new_feature_enabled) {
// Yeni özelliği etkinleştir
return NextResponse.next();
} else {
// Yeni özelliği devre dışı bırak (ör. alternatif bir sayfaya yönlendir)
return NextResponse.redirect(new URL('/alternative-page', request.url));
}
}
export const config = {
matcher: ['/new-feature'],
}
Bu middleware, bir API'den özellik bayraklarını alır ve new_feature_enabled
bayrağının ayarlanıp ayarlanmadığını kontrol eder. Eğer ayarlanmışsa, kullanıcı /new-feature
sayfasına erişebilir. Aksi takdirde, /alternative-page
sayfasına yönlendirilirler.
Küresel Perspektif: Yeni özellikleri farklı bölgelerdeki kullanıcılara aşamalı olarak sunmak için özellik bayraklarını kullanın. Bu, özelliği daha geniş bir kitleye yayınlamadan önce performansı izlemenize ve sorunları gidermenize olanak tanır. Ayrıca, özellik bayrağı sisteminizin küresel olarak ölçeklendiğinden ve kullanıcının konumundan bağımsız olarak tutarlı sonuçlar verdiğinden emin olun. Özellik sunumları için bölgesel düzenleyici kısıtlamaları göz önünde bulundurun.
İleri Düzey Teknikler
Middleware Zincirleme
Bir istek üzerinde bir dizi işlem gerçekleştirmek için birden fazla middleware fonksiyonunu birbirine zincirleyebilirsiniz. Bu, karmaşık mantığı daha küçük, daha yönetilebilir modüllere ayırmak için yararlı olabilir.
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const response = NextResponse.next();
// Birinci middleware fonksiyonu
const token = request.cookies.get('auth_token');
if (!token) {
return NextResponse.redirect(new URL('/login', request.url))
}
// İkinci middleware fonksiyonu
response.headers.set('x-middleware-custom', 'value');
return response;
}
export const config = {
matcher: ['/dashboard/:path*'],
}
Bu örnek, bir arada iki middleware gösterir. Birincisi kimlik doğrulama yapar ve ikincisi özel bir başlık ayarlar.
Ortam Değişkenlerini Kullanma
API anahtarları ve veritabanı kimlik bilgileri gibi hassas bilgileri middleware fonksiyonlarınızda sabit kodlamak yerine ortam değişkenlerinde saklayın. Bu, güvenliği artırır ve uygulamanızın yapılandırmasını yönetmeyi kolaylaştırır.
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
const API_KEY = process.env.API_KEY;
export async function middleware(request: NextRequest) {
const response = await fetch('https://api.example.com/data', {
headers: {
'X-API-Key': API_KEY,
},
});
// ...
}
export const config = {
matcher: ['/data'],
}
Bu örnekte, API_KEY
bir ortam değişkeninden alınır.
Hata Yönetimi
Beklenmedik hataların uygulamanızı çökertmesini önlemek için middleware fonksiyonlarınızda sağlam hata yönetimi uygulayın. İstisnaları yakalamak ve hataları uygun şekilde günlüğe kaydetmek için try...catch
bloklarını kullanın.
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export async function middleware(request: NextRequest) {
try {
const response = await fetch('https://api.example.com/data');
// ...
} catch (error) {
console.error('Veri alınırken hata oluştu:', error);
return NextResponse.error(); // Veya bir hata sayfasına yönlendir
}
}
export const config = {
matcher: ['/data'],
}
En İyi Uygulamalar
- Middleware fonksiyonlarını hafif tutun: Middleware'de yoğun hesaplama gerektiren işlemler yapmaktan kaçının, çünkü bu performansı etkileyebilir. Karmaşık işlemleri arka plan görevlerine veya özel servislere devredin.
- Eşleştiricileri etkili kullanın: Middleware'i yalnızca gerektiren rotalara uygulayın.
- Middleware'inizi kapsamlı bir şekilde test edin: Middleware fonksiyonlarınızın doğru çalıştığından emin olmak için birim testleri yazın.
- Middleware performansını izleyin: Middleware fonksiyonlarınızın performansını izlemek ve olası darboğazları belirlemek için izleme araçları kullanın.
- Middleware'inizi belgeleyin: Her bir middleware fonksiyonunun amacını ve işlevselliğini açıkça belgeleyin.
- Edge Runtime sınırlamalarını göz önünde bulundurun: Node.js API'lerinin eksikliği gibi Edge Runtime sınırlamalarının farkında olun. Kodunuzu buna göre ayarlayın.
Yaygın Sorunları Giderme
- Middleware çalışmıyor: Middleware'in doğru rotalara uygulandığından emin olmak için eşleştirici yapılandırmanızı iki kez kontrol edin.
- Performans sorunları: Yavaş middleware fonksiyonlarını belirleyin ve optimize edin. Performans darboğazlarını saptamak için profil oluşturma araçlarını kullanın.
- Edge Runtime uyumluluğu: Kodunuzun Edge Runtime ile uyumlu olduğundan emin olun. Desteklenmeyen Node.js API'lerini kullanmaktan kaçının.
- Çerez sorunları: Çerezlerin doğru şekilde ayarlandığını ve alındığını doğrulayın.
domain
,path
vesecure
gibi çerez özelliklerine dikkat edin. - Başlık çakışmaları: Middleware'de özel başlıklar ayarlarken olası başlık çakışmalarının farkında olun. Başlıklarınızın mevcut başlıkları istemeden geçersiz kılmadığından emin olun.
Sonuç
Next.js middleware, dinamik ve kişiselleştirilmiş web uygulamaları oluşturmak için güçlü bir araçtır. İstek yakalamada uzmanlaşarak, kimlik doğrulama ve yetkilendirmeden yönlendirme ve A/B testine kadar geniş bir yelpazede özellikler uygulayabilirsiniz. Bu kılavuzda belirtilen en iyi uygulamaları takip ederek, küresel kullanıcı tabanınızın ihtiyaçlarını karşılayan yüksek performanslı, güvenli ve ölçeklenebilir uygulamalar oluşturmak için Next.js middleware'den yararlanabilirsiniz. Next.js projelerinizde yeni olasılıkların kilidini açmak ve olağanüstü kullanıcı deneyimleri sunmak için middleware'in gücünü benimseyin.