Giriş: Web'de Veri Alışverişi
Modern web uygulamaları, kullanıcı deneyimini iyileştirmek için sayfayı tamamen yenilemeden sunucudan veri alabilmeli ve sunucuya veri gönderebilmelidir. Bu tür eşzamansız veri alışverişi, web uygulamalarının daha hızlı, daha duyarlı ve daha etkileşimli olmasını sağlar.
Bu derste, JavaScript'te web sunucularıyla veri alışverişi yapmak için kullanılan iki temel yaklaşımı inceleyeceğiz:
- AJAX (Asynchronous JavaScript and XML): Sayfayı yenilemeden sunucuyla veri alışverişi yapmanın geleneksel yöntemi. XMLHttpRequest (XHR) nesnesi kullanılır.
- Fetch API: Modern tarayıcılarda sunulan, Promise tabanlı, daha temiz ve güçlü bir HTTP istekleri yapma yöntemi.
Bu teknolojiler, tek sayfa uygulamaları (SPA), dinamik içerik yükleme, form gönderimi, API entegrasyonu ve daha birçok modern web özelliği için temel oluşturur.
AJAX Nedir?
AJAX (Asynchronous JavaScript and XML), web sayfalarının arka planda veri alışverişi yapmasını sağlayan bir web geliştirme tekniğidir. AJAX, sayfayı tamamen yenilemeden sunucudan veri almanıza, veri göndermenize ve sayfanın belirli bölümlerini güncellemenize olanak tanır.
AJAX'ın adındaki "XML" kısmı, başlangıçta veri formatı olarak XML kullanıldığını gösterir, ancak günümüzde AJAX istekleri genellikle JSON, HTML, metin veya diğer formatları kullanır.
AJAX'ın temel bileşeni, XMLHttpRequest
(XHR) nesnesidir. Bu nesne, JavaScript'in sunucuyla HTTP istekleri yapmasını sağlar.
XMLHttpRequest (XHR) Kullanımı
XHR nesnesi, AJAX isteklerini gerçekleştirmek için kullanılan geleneksel yöntemdir. Temel adımları şunlardır:
- XHR nesnesini oluşturmak
- İstek için olay dinleyicileri eklemek
- İsteği yapılandırmak (açmak)
- İsteği göndermek
- Yanıtı işlemek
function veriGetir() {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
console.log('Veri başarıyla alındı:', data);
} else {
console.error('Hata oluştu:', xhr.status, xhr.statusText);
}
}
};
xhr.onprogress = function(event) {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
console.log(`İlerleme: ${percentComplete.toFixed(2)}%`);
}
};
xhr.onerror = function() {
console.error('İstek sırasında bir hata oluştu.');
};
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send();
}
veriGetir();
POST İsteği ile Veri Gönderme
XHR ile sunucuya veri göndermek için POST, PUT veya diğer HTTP metodlarını kullanabilirsiniz:
function veriGonder() {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 201) {
const response = JSON.parse(xhr.responseText);
console.log('Veri başarıyla gönderildi:', response);
} else {
console.error('Hata oluştu:', xhr.status, xhr.statusText);
}
}
};
xhr.open('POST', 'https://jsonplaceholder.typicode.com/posts', true);
xhr.setRequestHeader('Content-Type', 'application/json');
const data = {
title: 'JavaScript AJAX Örneği',
body: 'Bu bir POST isteği örneğidir.',
userId: 1
};
xhr.send(JSON.stringify(data));
}
veriGonder();
XHR'nin Durumları (readyState)
XHR nesnesi, istek yaşam döngüsü boyunca farklı durumlardan geçer. readyState
özelliği, bu durumları temsil eder:
- 0 (UNSENT): XHR nesnesi oluşturuldu, ancak
open()
metodu henüz çağrılmadı. - 1 (OPENED):
open()
metodu çağrıldı. - 2 (HEADERS_RECEIVED):
send()
metodu çağrıldı ve başlıklar alındı. - 3 (LOADING): Yanıt yükleniyor (yanıtın bir kısmı alındı).
- 4 (DONE): İşlem tamamlandı (başarılı veya başarısız).
Genellikle, readyState === 4
durumunu kontrol ederiz, çünkü bu, isteğin tamamlandığını ve yanıtın hazır olduğunu gösterir.
Fetch API
Fetch API, modern tarayıcılarda sunulan, HTTP istekleri yapmak için daha temiz ve güçlü bir arayüzdür. XMLHttpRequest'e göre birçok avantajı vardır:
- Promise tabanlıdır, bu da daha temiz ve okunabilir kod yazmanızı sağlar.
- Async/await ile kullanılabilir.
- Daha basit ve anlaşılır bir API sunar.
- İstek ve yanıt nesneleri için daha fazla kontrol sağlar.
- Service Workers ile çalışabilir.
Temel Fetch Kullanımı
Fetch API'nin en temel kullanımı, bir URL'den veri almaktır:
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP hata! Durum: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('Veri alındı:', data);
})
.catch(error => {
console.error('Fetch hatası:', error);
});
async function veriGetir() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
if (!response.ok) {
throw new Error(`HTTP hata! Durum: ${response.status}`);
}
const data = await response.json();
console.log('Veri alındı (async/await):', data);
return data;
} catch (error) {
console.error('Fetch hatası (async/await):', error);
throw error;
}
}
veriGetir();
Not: fetch()
fonksiyonu, ağ hatası durumunda bir Promise reddi (rejection) döndürür, ancak HTTP hata durumları (404, 500 vb.) için Promise'ı reddetmez. Bu nedenle, response.ok
özelliğini kontrol etmek önemlidir.
Fetch ile POST İsteği
Fetch API ile veri göndermek için, ikinci bir argüman olarak istek seçeneklerini belirtebilirsiniz:
async function veriGonder() {
const veri = {
title: 'JavaScript Fetch API Örneği',
body: 'Bu bir POST isteği örneğidir.',
userId: 1
};
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(veri)
});
if (!response.ok) {
throw new Error(`HTTP hata! Durum: ${response.status}`);
}
const sonuc = await response.json();
console.log('Veri başarıyla gönderildi:', sonuc);
return sonuc;
} catch (error) {
console.error('Fetch hatası:', error);
throw error;
}
}
veriGonder();
Fetch İstek Seçenekleri
Fetch API, istek yapılandırması için birçok seçenek sunar:
method
: HTTP metodu (GET, POST, PUT, DELETE, vb.)headers
: İstek başlıkları (Headers nesnesi veya düz nesne)body
: İstek gövdesi (String, FormData, Blob, vb.)mode
: CORS modu (cors, no-cors, same-origin)credentials
: Kimlik bilgilerinin nasıl gönderileceği (omit, same-origin, include)cache
: Önbellek davranışı (default, no-store, reload, no-cache, force-cache, only-if-cached)redirect
: Yönlendirme davranışı (follow, error, manual)referrer
: Referrer bilgisireferrerPolicy
: Referrer politikasıintegrity
: Bütünlük doğrulamasıkeepalive
: Sayfa kapatıldıktan sonra isteğin devam edip etmeyeceğisignal
: İsteği iptal etmek için AbortSignal
async function gelismisIstek() {
const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => {
controller.abort();
console.log('İstek iptal edildi!');
}, 5000);
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123',
'X-Custom-Header': 'CustomValue'
},
body: JSON.stringify({
title: 'Gelişmiş Fetch Örneği',
body: 'Bu bir gelişmiş fetch isteği örneğidir.',
userId: 1
}),
mode: 'cors',
credentials: 'include',
cache: 'no-cache',
redirect: 'follow',
referrerPolicy: 'no-referrer',
signal: signal
});
if (!response.ok) {
throw new Error(`HTTP hata! Durum: ${response.status}`);
}
const data = await response.json();
console.log('Veri alındı:', data);
return data;
} catch (error) {
if (error.name === 'AbortError') {
console.log('İstek kullanıcı tarafından iptal edildi');
} else {
console.error('Fetch hatası:', error);
}
throw error;
}
}
gelismisIstek().catch(err => console.log('İşlem hatası:', err.message));
Yanıt İşleme
Fetch API, yanıtları işlemek için çeşitli metodlar sunar. Yanıt formatına bağlı olarak farklı metodlar kullanabilirsiniz:
Yanıt Formatları
response.json()
: Yanıtı JSON olarak ayrıştırır ve bir Promise döndürür.response.text()
: Yanıtı metin olarak alır.response.blob()
: Yanıtı Blob (ikili veri) olarak alır (resimler, dosyalar vb. için).response.formData()
: Yanıtı FormData nesnesi olarak alır.response.arrayBuffer()
: Yanıtı ArrayBuffer olarak alır (ham ikili veri için).
async function jsonVeriGetir() {
const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
const data = await response.json();
console.log('JSON veri:', data);
return data;
}
async function metinVeriGetir() {
const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
const text = await response.text();
console.log('Metin veri:', text);
return text;
}
async function resimGetir() {
const response = await fetch('https://via.placeholder.com/150');
const blob = await response.blob();
const imageUrl = URL.createObjectURL(blob);
const img = document.createElement('img');
img.src = imageUrl;
document.body.appendChild(img);
return imageUrl;
}
async function yanıtBilgileriniGetir() {
const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
console.log('Durum:', response.status, response.statusText);
console.log('Başlıklar:');
for (const [key, value] of response.headers) {
console.log(`${key}: ${value}`);
}
console.log('Content-Type:', response.headers.get('content-type'));
console.log('URL:', response.url);
console.log('Yönlendirildi mi:', response.redirected);
console.log('Tür:', response.type);
const data = await response.json();
return data;
}
Form Verisi Gönderme
Web uygulamalarında, form verilerini sunucuya göndermek yaygın bir işlemdir. Fetch API ile form verilerini göndermenin birkaç yolu vardır:
JSON Olarak Form Verisi Gönderme
async function formGonder() {
const formVeri = {
username: 'kullanici123',
email: 'ornek@example.com',
message: 'Merhaba, bu bir test mesajıdır.'
};
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formVeri)
});
if (!response.ok) {
throw new Error(`HTTP hata! Durum: ${response.status}`);
}
const sonuc = await response.json();
console.log('Form başarıyla gönderildi:', sonuc);
return sonuc;
} catch (error) {
console.error('Form gönderme hatası:', error);
throw error;
}
}
FormData Nesnesi Kullanma
FormData
nesnesi, form verilerini kolayca toplamak ve göndermek için kullanılabilir. Özellikle dosya yüklemeleri için kullanışlıdır.
async function formDataGonder() {
const form = document.getElementById('userForm');
const formData = new FormData(form);
formData.append('extraField', 'Ekstra veri');
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error(`HTTP hata! Durum: ${response.status}`);
}
const sonuc = await response.json();
console.log('Form başarıyla gönderildi:', sonuc);
return sonuc;
} catch (error) {
console.error('Form gönderme hatası:', error);
throw error;
}
}
async function manuelFormDataGonder() {
const formData = new FormData();
formData.append('username', 'kullanici123');
formData.append('email', 'ornek@example.com');
formData.append('message', 'Merhaba, bu bir test mesajıdır.');
const fileInput = document.querySelector('input[type="file"]');
if (fileInput.files.length > 0) {
formData.append('avatar', fileInput.files[0]);
}
for (const pair of formData.entries()) {
console.log(`${pair[0]}: ${pair[1]}`);
}
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: formData
});
const sonuc = await response.json();
return sonuc;
}
Hata Yönetimi ve İstek İptali
Fetch API ile yapılan isteklerde hata yönetimi ve istek iptali önemli konulardır.
Hata Yönetimi
Fetch API'de hata yönetimi için dikkat edilmesi gereken iki durum vardır:
- Ağ Hataları: Fetch, ağ hatası durumunda Promise'ı reddeder (reject).
- HTTP Hata Durumları: Fetch, 404 veya 500 gibi HTTP hata durumlarında Promise'ı reddetmez. Bu nedenle,
response.ok
özelliğini kontrol etmelisiniz.
async function veriGetirHataYonetimi() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/nonexistent');
if (!response.ok) {
const errorMsg = `HTTP Hata! Durum: ${response.status}`;
const error = new Error(errorMsg);
error.status = response.status;
error.response = response;
throw error;
}
const data = await response.json();
return data;
} catch (error) {
if (error.status) {
console.error(`HTTP Hatası: ${error.status}`);
switch (error.status) {
case 404:
console.error('Kaynak bulunamadı!');
break;
case 401:
console.error('Yetkilendirme hatası!');
break;
case 500:
console.error('Sunucu hatası!');
break;
default:
console.error('Bilinmeyen hata!');
}
} else {
console.error('Ağ hatası veya başka bir hata:', error.message);
}
throw error;
}
}
İstek İptali
Fetch API, AbortController
ve AbortSignal
arayüzleri ile istekleri iptal etme yeteneği sunar. Bu, uzun süren istekleri iptal etmek veya kullanıcı bir sayfadan ayrıldığında istekleri temizlemek için kullanışlıdır.
function istekIptalOrnek() {
const controller = new AbortController();
const signal = controller.signal;
const iptalBtn = document.getElementById('iptalBtn');
iptalBtn.addEventListener('click', () => {
controller.abort();
console.log('İstek kullanıcı tarafından iptal edildi!');
});
const timeout = setTimeout(() => {
controller.abort();
console.log('İstek zaman aşımı nedeniyle iptal edildi!');
}, 5000);
fetch('https://jsonplaceholder.typicode.com/photos', {
signal: signal
})
.then(response => {
clearTimeout(timeout);
return response.json();
})
.then(data => {
console.log(`${data.length} fotoğraf alındı`);
})
.catch(err => {
if (err.name === 'AbortError') {
console.log('İstek iptal edildi');
} else {
console.error('Fetch hatası:', err);
}
});
}
async function istekIptalAsync() {
const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => {
controller.abort();
console.log('İstek otomatik olarak iptal edildi');
}, 3000);
try {
const response = await fetch('https://jsonplaceholder.typicode.com/photos', {
signal: signal
});
const data = await response.json();
console.log(`${data.length} fotoğraf alındı`);
} catch (err) {
if (err.name === 'AbortError') {
console.log('İstek iptal edildi');
} else {
console.error('Fetch hatası:', err);
}
}
}
Alıştırmalar
- JSONPlaceholder API'sinden (
https://jsonplaceholder.typicode.com/posts
) tüm gönderileri çeken ve bunları bir HTML listesinde gösteren bir fonksiyon yazın. - Bir kullanıcı ID'si alan ve o kullanıcının gönderilerini (
https://jsonplaceholder.typicode.com/posts?userId=1
) çeken bir fonksiyon yazın. Async/await kullanın ve hata yönetimini ekleyin. - Bir form oluşturun ve form verilerini
FormData
kullanarak https://jsonplaceholder.typicode.com/posts
adresine POST isteği ile gönderin. - Bir istek yapın ve 3 saniye sonra otomatik olarak iptal eden bir fonksiyon yazın. İptal durumunu uygun şekilde ele alın.
- Paralel olarak birden fazla API isteği yapan (örneğin, kullanıcılar, gönderiler ve yorumlar) ve tüm sonuçları birleştiren bir fonksiyon yazın.
Promise.all()
kullanın.
Bu derste, web uygulamalarında veri alışverişi için kullanılan iki temel yaklaşımı inceledik:
- AJAX (XMLHttpRequest):
- Geleneksel yöntem, tüm tarayıcılarda desteklenir.
- Callback tabanlı API, daha karmaşık kod yapısı.
readyState
ve status
kontrolleri gerektirir.- Olay dinleyicileri (
onreadystatechange
, onload
, onerror
vb.) kullanır.
- Fetch API:
- Modern, Promise tabanlı API, daha temiz kod yapısı.
- Async/await ile kullanılabilir.
- İstek ve yanıt nesneleri için daha fazla kontrol.
AbortController
ile istek iptali desteği.- HTTP hata durumlarını manuel olarak kontrol etmek gerekir (
response.ok
). - Çeşitli yanıt formatları için metodlar (
json()
, text()
, blob()
vb.).
Modern web geliştirmede, Fetch API genellikle tercih edilen yöntemdir, çünkü daha temiz, daha okunabilir ve daha güçlü bir API sunar. Ancak, eski tarayıcıları desteklemeniz gerekiyorsa, XMLHttpRequest veya bir polyfill kullanmanız gerekebilir.
Bir sonraki derste, modern web uygulamalarında yaygın olarak kullanılan JavaScript modülleri ve modül sistemlerini inceleyeceğiz.