Gelişmiş Fetch API tekniklerinde ustalaşın: optimum performans için istekleri yakalama ve yanıt önbellekleme uygulama. Küresel uygulamalar için en iyi pratikleri öğrenin.
Fetch API İleri Düzey: İstek Yakalama ve Yanıt Önbellekleme
Fetch API, modern JavaScript'te ağ istekleri yapmak için standart haline gelmiştir. Temel kullanımı basit olsa da, tam potansiyelini ortaya çıkarmak için istek yakalama ve yanıt önbellekleme gibi ileri düzey teknikleri anlamak gerekir. Bu makale, yüksek performanslı, küresel olarak erişilebilir web uygulamaları oluşturmak için pratik örnekler ve en iyi uygulamaları sunarak bu kavramları ayrıntılı olarak inceleyecektir.
Fetch API'sini Anlamak
Fetch API, ağ üzerinden kaynakları getirmek için güçlü ve esnek bir arayüz sağlar. Asenkron işlemleri yönetmeyi ve anlamlandırmayı kolaylaştıran Promise'leri kullanır. İleri düzey konulara dalmadan önce, temel bilgilere kısaca göz atalım:
Temel Fetch Kullanımı
Basit bir Fetch isteği şu şekilde görünür:
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('Data:', data);
})
.catch(error => {
console.error('Fetch error:', error);
});
Bu kod, belirtilen URL'den veri alır, HTTP hatalarını kontrol eder, yanıtı JSON olarak ayrıştırır ve veriyi konsola yazar. Sağlam bir uygulama sağlamak için hata yönetimi çok önemlidir.
İstek Yakalama
İstek yakalama, sunucuya gönderilmeden önce ağ isteklerini değiştirmeyi veya gözlemlemeyi içerir. Bu, aşağıdakiler de dahil olmak üzere çeşitli amaçlar için yararlı olabilir:
- Kimlik doğrulama başlıkları ekleme
- İstek verisini dönüştürme
- Hata ayıklama için istekleri kaydetme
- Geliştirme sırasında API yanıtlarını taklit etme
İstek yakalama genellikle web uygulaması ile ağ arasında bir proxy görevi gören bir Service Worker kullanılarak gerçekleştirilir.
Service Worker'lar: Yakalamanın Temeli
Service Worker, ana tarayıcı iş parçacığından ayrı olarak arka planda çalışan bir JavaScript dosyasıdır. Ağ isteklerini yakalayabilir, yanıtları önbelleğe alabilir ve çevrimdışı işlevsellik sağlayabilir. Bir Service Worker kullanmak için önce onu kaydetmeniz gerekir:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
}
Bu kod, tarayıcının Service Worker'ları destekleyip desteklemediğini kontrol eder ve service-worker.js
dosyasını kaydeder. Kapsam (scope), Service Worker'ın hangi URL'leri kontrol edeceğini tanımlar.
İstek Yakalamayı Uygulama
service-worker.js
dosyası içinde, fetch
olayını kullanarak istekleri yakalayabilirsiniz:
self.addEventListener('fetch', event => {
// Intercept all fetch requests
event.respondWith(
new Promise(resolve => {
// Clone the request to avoid modifying the original
const req = event.request.clone();
// Modify the request (e.g., add an authentication header)
const headers = new Headers(req.headers);
headers.append('Authorization', 'Bearer your_api_key');
const modifiedReq = new Request(req.url, {
method: req.method,
headers: headers,
body: req.body,
mode: 'cors',
credentials: req.credentials,
cache: req.cache,
redirect: req.redirect,
referrer: req.referrer,
integrity: req.integrity
});
// Make the modified request
fetch(modifiedReq)
.then(response => resolve(response))
.catch(error => {
console.error('Fetch error in Service Worker:', error);
// Optionally, return a default response or error page
resolve(new Response('Offline', { status: 503, statusText: 'Service Unavailable' }));
});
})
);
});
Bu kod, her fetch
isteğini yakalar, kopyalar, bir Authorization
başlığı ekler ve ardından değiştirilmiş isteği yapar. event.respondWith()
yöntemi, tarayıcıya isteği nasıl ele alacağını söyler. İsteği kopyalamak çok önemlidir; aksi takdirde, beklenmedik davranışlara yol açabilecek olan orijinal isteği değiştirmiş olursunuz. Ayrıca uyumluluğu sağlamak için tüm orijinal istek seçeneklerini ilettiğinden emin olur. Hata yönetimine dikkat edin: fetch başarısız olursa (örneğin, çevrimdışı iken) bir geri dönüş sağlamak önemlidir.
Örnek: Kimlik Doğrulama Başlıkları Ekleme
İstek yakalamanın yaygın bir kullanım durumu, API isteklerine kimlik doğrulama başlıkları eklemektir. Bu, korunan kaynaklara yalnızca yetkili kullanıcıların erişebilmesini sağlar.
self.addEventListener('fetch', event => {
if (event.request.url.startsWith('https://api.example.com')) {
event.respondWith(
new Promise(resolve => {
const req = event.request.clone();
const headers = new Headers(req.headers);
// Replace with actual authentication logic (e.g., retrieving token from local storage)
const token = localStorage.getItem('api_token');
if (token) {
headers.append('Authorization', `Bearer ${token}`);
} else {
console.warn("No API token found, request may fail.");
}
const modifiedReq = new Request(req.url, {
method: req.method,
headers: headers,
body: req.body,
mode: 'cors',
credentials: req.credentials,
cache: req.cache,
redirect: req.redirect,
referrer: req.referrer,
integrity: req.integrity
});
fetch(modifiedReq)
.then(response => resolve(response))
.catch(error => {
console.error('Fetch error in Service Worker:', error);
resolve(new Response('Offline', { status: 503, statusText: 'Service Unavailable' }));
});
})
);
} else {
// Let the browser handle the request as usual
event.respondWith(fetch(event.request));
}
});
Bu kod, https://api.example.com
ile başlayan isteklere bir Authorization
başlığı ekler. API anahtarını yerel depolamadan (local storage) alır. HTTPS ve güvenli depolama gibi uygun anahtar yönetimi ve güvenlik önlemlerini uygulamak çok önemlidir.
Örnek: İstek Verisini Dönüştürme
İstek yakalama, sunucuya gönderilmeden önce istek verisini dönüştürmek için de kullanılabilir. Örneğin, veriyi belirli bir formata dönüştürmek veya ek parametreler eklemek isteyebilirsiniz.
self.addEventListener('fetch', event => {
if (event.request.url.includes('/submit-form')) {
event.respondWith(
new Promise(resolve => {
const req = event.request.clone();
req.text().then(body => {
try {
const parsedBody = JSON.parse(body);
// Transform the data (e.g., add a timestamp)
parsedBody.timestamp = new Date().toISOString();
// Convert the transformed data back to JSON
const transformedBody = JSON.stringify(parsedBody);
const modifiedReq = new Request(req.url, {
method: req.method,
headers: req.headers,
body: transformedBody,
mode: 'cors',
credentials: req.credentials,
cache: req.cache,
redirect: req.redirect,
referrer: req.referrer,
integrity: req.integrity
});
fetch(modifiedReq)
.then(response => resolve(response))
.catch(error => {
console.error('Fetch error in Service Worker:', error);
resolve(new Response('Offline', { status: 503, statusText: 'Service Unavailable' }));
});
} catch (error) {
console.error("Error parsing request body:", error);
resolve(fetch(event.request)); // Fallback to original request
}
});
})
);
} else {
event.respondWith(fetch(event.request));
}
});
Bu kod, /submit-form
adresine yapılan istekleri yakalar, istek gövdesini JSON olarak ayrıştırır, bir zaman damgası ekler ve ardından dönüştürülmüş veriyi sunucuya gönderir. İstek gövdesi geçerli bir JSON değilse uygulamanın bozulmamasını sağlamak için hata yönetimi esastır.
Yanıt Önbellekleme
Yanıt önbellekleme, API isteklerinden gelen yanıtların tarayıcının önbelleğinde saklanmasını içerir. Bu, ağ isteklerinin sayısını azaltarak performansı önemli ölçüde artırabilir. Önbelleğe alınmış bir yanıt mevcut olduğunda, tarayıcı bunu sunucuya yeni bir istekte bulunmadan doğrudan önbellekten sunabilir.
Yanıt Önbelleklemenin Faydaları
- Geliştirilmiş Performans: Daha hızlı yükleme süreleri ve daha duyarlı bir kullanıcı deneyimi.
- Azaltılmış Bant Genişliği Tüketimi: Ağ üzerinden daha az veri aktarılır, bu da hem kullanıcı hem de sunucu için bant genişliğinden tasarruf sağlar.
- Çevrimdışı İşlevsellik: Önbelleğe alınmış yanıtlar, kullanıcı çevrimdışı olduğunda bile sunularak kesintisiz bir deneyim sağlar.
- Maliyet Tasarrufu: Düşük bant genişliği tüketimi, özellikle pahalı veya sınırlı veri planlarına sahip bölgelerde hem kullanıcılar hem de hizmet sağlayıcılar için daha düşük maliyetler anlamına gelir.
Service Worker'lar ile Yanıt Önbellekleme Uygulama
Service Worker'lar, yanıt önbellekleme uygulamak için güçlü bir mekanizma sağlar. Yanıtları depolamak ve geri almak için Cache
API'sini kullanabilirsiniz.
const cacheName = 'my-app-cache-v1';
const cacheableUrls = [
'/',
'/index.html',
'/styles.css',
'/script.js',
'https://api.example.com/data'
];
// Install event: Cache static assets
self.addEventListener('install', event => {
event.waitUntil(
caches.open(cacheName)
.then(cache => {
console.log('Caching app shell');
return cache.addAll(cacheableUrls);
})
);
});
// Activate event: Clean up old caches
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.filter(name => name !== cacheName)
.map(name => caches.delete(name))
);
})
);
});
// Fetch event: Serve cached responses or fetch from the network
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
// Cache hit - return response
if (response) {
return response;
}
// Not in cache - fetch from network
return fetch(event.request).then(
response => {
// Check if we received a valid response
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// Clone the response (because it's a stream and can only be consumed once)
const responseToCache = response.clone();
caches.open(cacheName)
.then(cache => {
cache.put(event.request, responseToCache);
});
return response;
}
).catch(error => {
// Handle network error
console.error("Fetch failed:", error);
// Optionally, provide a fallback response (e.g., offline page)
return caches.match('/offline.html');
});
})
);
});
Bu kod, install olayı sırasında statik varlıkları önbelleğe alır ve fetch olayı sırasında önbelleğe alınmış yanıtları sunar. Bir yanıt önbellekte bulunamazsa, ağdan getirir, önbelleğe alır ve sonra döndürür. `activate` olayı, Service Worker güncellendiğinde eski önbellekleri temizlemek için kullanılır. Bu yaklaşım ayrıca yalnızca geçerli yanıtların (durum 200 ve tür 'basic') önbelleğe alınmasını sağlar.
Önbellek Stratejileri
Uygulamanızın ihtiyaçlarına bağlı olarak kullanabileceğiniz birkaç farklı önbellek stratejisi vardır:
- Önce Önbellek (Cache-First): Yanıtı önce önbellekten sunmaya çalışın. Bulunamazsa, ağdan getirin ve önbelleğe alın. Bu, statik varlıklar ve sık değişmeyen kaynaklar için iyidir.
- Önce Ağ (Network-First): Yanıtı önce ağdan getirmeye çalışın. Bu başarısız olursa, önbellekten sunun. Bu, güncel olması gereken dinamik veriler için iyidir.
- Önbellek, sonra Ağ (Cache, then Network): Yanıtı hemen önbellekten sunun ve ardından önbelleği ağdan gelen en son sürümle güncelleyin. Bu, hızlı bir ilk yükleme sağlar ve kullanıcının (sonunda) her zaman en son veriye sahip olmasını garanti eder.
- Eskimişken Yeniden Doğrula (Stale-While-Revalidate): Önbelleğe alınmış bir yanıtı hemen döndürürken aynı anda ağda güncellenmiş bir sürüm olup olmadığını kontrol edin. Daha yeni bir sürüm mevcutsa önbelleği arka planda güncelleyin. "Önbellek, sonra Ağ" stratejisine benzer ancak daha kesintisiz bir kullanıcı deneyimi sunar.
Önbellek stratejisi seçimi, uygulamanızın özel gereksinimlerine bağlıdır. Güncelleme sıklığı, tazeliğin önemi ve mevcut bant genişliği gibi faktörleri göz önünde bulundurun.
Örnek: API Yanıtlarını Önbelleğe Alma
İşte Önce Önbellek (Cache-First) stratejisini kullanarak API yanıtlarını önbelleğe alma örneği:
self.addEventListener('fetch', event => {
if (event.request.url.startsWith('https://api.example.com')) {
event.respondWith(
caches.match(event.request)
.then(response => {
// Cache hit - return response
if (response) {
return response;
}
// Not in cache - fetch from network
return fetch(event.request).then(
response => {
// Check if we received a valid response
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// Clone the response (because it's a stream and can only be consumed once)
const responseToCache = response.clone();
caches.open(cacheName)
.then(cache => {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
} else {
// Let the browser handle the request as usual
event.respondWith(fetch(event.request));
}
});
Bu kod, https://api.example.com
adresinden gelen API yanıtlarını önbelleğe alır. Bir istek yapıldığında, Service Worker önce yanıtın önbellekte olup olmadığını kontrol eder. Eğer varsa, önbelleğe alınmış yanıt döndürülür. Değilse, istek ağa yapılır ve yanıt döndürülmeden önce önbelleğe alınır.
İleri Düzey Hususlar
Önbellek Geçersizleştirme
Önbelleklemenin en büyük zorluklarından biri önbellek geçersizleştirmedir. Sunucudaki veriler değiştiğinde, önbelleğin güncellendiğinden emin olmanız gerekir. Önbellek geçersizleştirme için birkaç strateji vardır:
- Önbellek Bozma (Cache Busting): Kaynağın URL'sine bir sürüm numarası veya zaman damgası ekleyin. Kaynak değiştiğinde URL de değişir ve tarayıcı yeni sürümü getirir.
- Zaman Tabanlı Sona Erme: Önbelleğe alınmış yanıtlar için maksimum bir yaş belirleyin. Sona erme süresinden sonra, tarayıcı sunucudan yeni bir sürüm getirecektir. Maksimum yaşı belirtmek için
Cache-Control
başlığını kullanın. - Manuel Geçersizleştirme: Önbelleğe alınmış yanıtları manuel olarak kaldırmak için
caches.delete()
yöntemini kullanın. Bu, sunucu tarafı bir olay veya kullanıcı eylemi tarafından tetiklenebilir. - Gerçek Zamanlı Güncellemeler için WebSockets: Gerektiğinde önbelleği geçersiz kılarak güncellemeleri sunucudan istemciye göndermek için WebSockets kullanın.
İçerik Dağıtım Ağları (CDN'ler)
İçerik Dağıtım Ağları (CDN'ler), içeriği kullanıcılara daha yakın bir yerde önbelleğe alan dağıtılmış sunucu ağlarıdır. Bir CDN kullanmak, gecikmeyi ve bant genişliği tüketimini azaltarak dünya çapındaki kullanıcılar için performansı önemli ölçüde artırabilir. Popüler CDN sağlayıcıları arasında Cloudflare, Amazon CloudFront ve Akamai bulunur. CDN'lerle entegrasyon yaparken, optimum önbellekleme davranışı için `Cache-Control` başlıklarının doğru şekilde yapılandırıldığından emin olun.
Güvenlik Hususları
İstek yakalama ve yanıt önbellekleme uygularken, güvenlik sonuçlarını dikkate almak esastır:
- HTTPS: Aktarımdaki verileri korumak için her zaman HTTPS kullanın.
- CORS: Kaynaklara yetkisiz erişimi önlemek için Çapraz Köken Kaynak Paylaşımını (CORS) doğru şekilde yapılandırın.
- Veri Temizleme: Siteler arası komut dosyası çalıştırma (XSS) saldırılarını önlemek için kullanıcı girdilerini temizleyin.
- Güvenli Depolama: API anahtarları ve jetonlar gibi hassas verileri güvenli bir şekilde saklayın (örneğin, yalnızca HTTPS çerezleri veya güvenli bir depolama API'si kullanarak).
- Alt Kaynak Bütünlüğü (SRI): Üçüncü taraf CDN'lerden alınan kaynakların kurcalanmadığından emin olmak için SRI kullanın.
Service Worker Hata Ayıklaması
Service Worker'larda hata ayıklamak zor olabilir, ancak tarayıcının geliştirici araçları yardımcı olacak birkaç özellik sunar:
- Uygulama Sekmesi: Chrome Geliştirici Araçları'ndaki Uygulama sekmesi, durumları, kapsamları ve önbellek depolamaları dahil olmak üzere Service Worker'lar hakkında bilgi sağlar.
- Konsol Kaydı: Service Worker etkinliği hakkında bilgi kaydetmek için
console.log()
ifadelerini kullanın. - Kesme Noktaları (Breakpoints): Yürütmeyi adım adım izlemek ve değişkenleri incelemek için Service Worker kodunda kesme noktaları ayarlayın.
- Yeniden Yüklemede Güncelle: Sayfayı her yeniden yüklediğinizde Service Worker'ın güncellendiğinden emin olmak için Uygulama sekmesinde "Yeniden yüklemede güncelle" seçeneğini etkinleştirin.
- Service Worker Kaydını Kaldır: Sorunları gidermek veya temiz bir başlangıç yapmak için Service Worker kaydını kaldırmak için Uygulama sekmesindeki "Kaydı Kaldır" düğmesini kullanın.
Sonuç
İstek yakalama ve yanıt önbellekleme, web uygulamalarının performansını ve kullanıcı deneyimini önemli ölçüde artırabilen güçlü tekniklerdir. Service Worker'ları kullanarak, ağ isteklerini yakalayabilir, gerektiği gibi değiştirebilir ve çevrimdışı işlevsellik ve daha hızlı yükleme süreleri için yanıtları önbelleğe alabilirsiniz. Doğru uygulandığında, bu teknikler zorlu ağ koşullarında bile kesintisiz bir kullanıcı deneyimi sunan yüksek performanslı, küresel olarak erişilebilir web uygulamaları oluşturmanıza yardımcı olabilir. Optimum erişilebilirlik ve kapsayıcılık sağlamak için bu teknikleri uygularken dünya çapındaki kullanıcıların karşılaştığı çeşitli ağ koşullarını ve veri maliyetlerini göz önünde bulundurun. Hassas verileri korumak ve güvenlik açıklarını önlemek için her zaman güvenliğe öncelik verin.
Bu ileri düzey Fetch API tekniklerinde ustalaşarak, web geliştirme becerilerinizi bir sonraki seviyeye taşıyabilir ve gerçekten olağanüstü web uygulamaları oluşturabilirsiniz.