---
title: 'Oturum Yenileme'
source: 'https://academia.sh/tr/kurslar/frontend-mimarisi/oturum-yenileme'
course: 'Uygulama Mimarisi: Yönlendirme, Durum ve Veri'
language: tr
updated: '2026-08-17T18:09:20+00:00'
license: 'CC BY-SA 4.0'
---

# Oturum Yenileme

Kısa ömürlü belirtecin kullanıcıya yansımadan tazelenmesi, eşzamanlı yetki hatalarının tek bir yenilemede toplanması, yenileme belirtecinin dönüşümü ve yeniden kullanım saptaması, çıkışın her yerde etkili olması.

Önceki ders belirtecin kısa ömürlü olmasını bir savunma olarak sundu. Kısa ömrün bedeli
belli: on beş dakikada bir oturumun düşmesi. Gözlemci ölçüm formunu doldururken sürenin
dolması, gönderimin 401 ile dönmesi ve yazılan her şeyin tehlikeye girmesi demektir.

Bu ders bedeli ödemeden kısa ömrü koruyan düzeni kurar. Kullanıcının fark etmediği bir
tazeleme, aynı anda düşen birden çok isteğin tek bir tazelemede toplanması, tazeleme
kanalının kendisinin korunması ve oturumun her yerde aynı anda kapanması.

## Yenilemenin Üç Tetikleyicisi

**Tepkisel yenileme**, 401 yanıtı alındığında yapılır. İstek katmanı yanıtı görür,
belirteci tazeler, isteği bir kez yineler. En basit ve en dayanıklı yoldur: sunucunun
kararına dayanır, istemcinin saatine güvenmez.

**Önden yenileme**, sürenin dolmasına az kaldığında yapılır. Önceki dersteki süre denetimi
buna hizmet eder; belirtecin `exp` alanı okunur ve bir pay bırakılarak erkenden tazelenir.
Kazancı, kullanıcının bir isteğin iki kez gitmesini beklememesidir. Tek başına yeterli
değildir — istemcinin saati yanlış olabilir, sunucu belirteci erken iptal etmiş olabilir —
bu yüzden tepkisel yenilemenin yerine geçmez, onunla birlikte çalışır.

**Açılıştaki sessiz oturum kurma**, sayfa yenilendiğinde yapılır. Erişim belirtecini
bellekte tutan bir düzende sayfa yenilendiğinde elde bir şey kalmaz; uygulama açılırken
yenileme kanalını bir kez dener. Başarılı olursa oturum kaldığı yerden sürer, başarısız
olursa oturum kapalı sayılır. Önceki derste anılan `bilinmiyor` kimlik durumu tam olarak
bu deneme süresince geçerlidir.

## Tek Uçuş

Bir ekran açıldığında genellikle birkaç istek birden gider: istasyon listesi, ölçüm
geçmişi, özet, uyarılar. Belirtecin süresi dolduysa dördü de 401 alır. Her biri kendi
yenilemesini başlatırsa sunucuya dört yenileme isteği gider — ve belirteç dönüşümü varsa
üçü geçersiz belirteçle gelir, oturum kapanır.

Çözüm **tek uçuş (single flight)** düzenidir: yenileme başlatılırken üretilen söz saklanır,
aynı anda yenileme isteyen herkes o sözü bekler.

```js
// oturum-yenileme.mjs — sessiz yenileme, tek ucus ve yeniden kullanim saptamasi
import http from "node:http";

// --- Sunucu -----------------------------------------------------------------
let surum = 1;
let gecerliErisim = "e1", gecerliYenileme = "y1";
let oturumAcik = true, yenilemeSayaci = 0;
const kullanilmis = new Set();

const govdeyiOku = (istek) => new Promise((coz) => {
  let m = ""; istek.on("data", (p) => (m += p)); istek.on("end", () => coz(m ? JSON.parse(m) : {}));
});

const sunucu = http.createServer(async (istek, yanit) => {
  const yol = new URL(istek.url, "http://127.0.0.1").pathname;
  const gonder = (durum, govde) => {
    yanit.writeHead(durum, { "content-type": "application/json" });
    yanit.end(JSON.stringify(govde));
  };

  if (yol === "/olcumler") {
    if (!oturumAcik || istek.headers.authorization !== `Bearer ${gecerliErisim}`)
      return gonder(401, { kod: "kimlik_yok" });
    return gonder(200, { kayit: "o-114", surum });
  }

  if (yol === "/oturum/yenile") {
    const { yenileme } = await govdeyiOku(istek);
    if (kullanilmis.has(yenileme)) {          // ayni belirtec ikinci kez: aile iptal
      oturumAcik = false;
      return gonder(401, { kod: "yeniden_kullanim" });
    }
    if (!oturumAcik || yenileme !== gecerliYenileme)
      return gonder(401, { kod: "yenileme_gecersiz" });
    kullanilmis.add(yenileme);
    surum += 1; yenilemeSayaci += 1;
    gecerliErisim = `e${surum}`; gecerliYenileme = `y${surum}`;
    return gonder(200, { erisim: gecerliErisim, yenileme: gecerliYenileme });
  }

  if (yol === "/oturum/kapat") { oturumAcik = false; return gonder(204, {}); }
  gonder(404, { kod: "yol_yok" });
});
await new Promise((coz) => sunucu.listen(0, "127.0.0.1", coz));
const TABAN = `http://127.0.0.1:${sunucu.address().port}`;

// --- Istemci ----------------------------------------------------------------
const oturum = { erisim: "e0", yenileme: "y1", acik: true };   // erisim bilerek eskitildi
let ucustaki = null;

function yenile(kullanilanErisim) {
  // Baskasi zaten yeniledi: bu istek yeni belirtecle dogrudan tekrarlanir.
  if (kullanilanErisim !== oturum.erisim) return Promise.resolve(true);
  if (ucustaki) return ucustaki;

  ucustaki = (async () => {
    const yanit = await fetch(`${TABAN}/oturum/yenile`, {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ yenileme: oturum.yenileme }),
    });
    if (!yanit.ok) { oturum.acik = false; return false; }
    const govde = await yanit.json();
    oturum.erisim = govde.erisim;
    oturum.yenileme = govde.yenileme;         // donusum: eski belirtec artik gecersiz
    return true;
  })();
  ucustaki.finally(() => { ucustaki = null; });
  return ucustaki;
}

async function istek(ad) {
  if (!oturum.acik) return `${ad}: oturum kapalı`;
  const kullanilan = oturum.erisim;
  let yanit = await fetch(`${TABAN}/olcumler`,
    { headers: { authorization: `Bearer ${kullanilan}` } });
  if (yanit.status !== 401) return `${ad}: ${yanit.status}`;

  const yenilendi = await yenile(kullanilan);
  if (!yenilendi) return `${ad}: oturum düştü`;

  yanit = await fetch(`${TABAN}/olcumler`,
    { headers: { authorization: `Bearer ${oturum.erisim}` } });
  const govde = await yanit.json();
  return `${ad}: ${yanit.status} sürüm=${govde.surum ?? "-"}`;
}

// --- 1. Ayni anda dusen dort istek -----------------------------------------
const sonuclar = await Promise.all(["istasyon", "geçmiş", "özet", "uyarı"].map(istek));
sonuclar.forEach((s) => console.log("  " + s));
console.log("sunucudaki yenileme sayısı:", yenilemeSayaci);

// --- 2. Eski yenileme belirtecinin ikinci kez kullanilmasi ------------------
const eski = "y1";
const y = await fetch(`${TABAN}/oturum/yenile`, {
  method: "POST", headers: { "content-type": "application/json" },
  body: JSON.stringify({ yenileme: eski }),
});
console.log("\neski yenileme belirteci →", y.status, JSON.stringify(await y.json()));

// --- 3. Aile iptal edildikten sonra ----------------------------------------
oturum.acik = true;                            // istemci henuz bilmiyor
console.log("iptal sonrası istek        →", await istek("geçmiş"));
console.log("istemcinin oturum durumu   :", oturum.acik ? "açık" : "kapalı");

sunucu.close();
```

```
  istasyon: 200 sürüm=2
  geçmiş: 200 sürüm=2
  özet: 200 sürüm=2
  uyarı: 200 sürüm=2
sunucudaki yenileme sayısı: 1

eski yenileme belirteci → 401 {"kod":"yeniden_kullanim"}
iptal sonrası istek        → geçmiş: oturum düştü
istemcinin oturum durumu   : kapalı
```

## Çıktının Okunması

Dört istek de başarıyla döndü ve sunucudaki yenileme sayacı **bir** gösterdi. Dört ayrı
çağrı noktası tek bir yenilemeyi paylaştı; hiçbiri bir diğerinin varlığını bilmiyor.

Toplamayı sağlayan iki koruma var ve ikisi de gereklidir. Birincisi **uçuştaki söz**: bir
yenileme sürerken gelen ikinci istek yenisini başlatmaz, sürene katılır. İkincisi
**kullanılan belirtecin karşılaştırılması**: 401'i geç fark eden bir istek, yenileme çoktan
bitmişse hiç yenileme istemez, yeni belirteçle doğrudan yinelenir. Yalnız birincisi
yazıldığında, yenileme bittikten hemen sonra gelen bir 401 gereksiz bir ikinci yenileme
başlatır.

`surum=2` değeri, dört isteğin de **yenilemeden sonraki** belirteçle yanıtlandığını
gösteriyor. Yineleme, yenileme sırasında değişmiş olan belirteci okumak zorundadır;
isteğin başında yakalanan eski değeri kullanmak yinelemeyi de 401'e düşürürdü.

## Dönüşüm ve Yeniden Kullanım Saptaması

Yenileme belirteci uzun ömürlüdür ve bu onu oturumun en değerli parçası yapar. İki
düzenek riski daraltır.

**Dönüşüm (rotation)**: her yenilemede yalnız erişim belirteci değil, yenileme belirteci de
değişir. Kullanılmış olan bir daha kabul edilmez. Böylece bir yenileme belirtecinin
kullanılabilir ömrü, bir sonraki yenilemeye kadardır.

**Yeniden kullanım saptaması**: kullanılmış bir yenileme belirteci ikinci kez gelirse,
sunucu bunu tek bir istemcinin hatası saymaz. İki olasılık vardır — ya bir kopya
dolaşımdadır ya da yenileme yanıtı istemciye ulaşmadan bağlantı kopmuştur. İkisini ayırt
etmek mümkün olmadığı için sunucu güvenli tarafı seçer ve o oturuma bağlı bütün
belirteçleri iptal eder. Çıktının ikinci bölümü bunu gösteriyor: `y1` ikinci kez
gönderildiğinde yanıt `yeniden_kullanim` oldu.

Üçüncü bölüm iptalin sonucunu gösteriyor. İstemci oturumun kapandığını bilmiyordu ve
isteğini gönderdi; 401 aldı, yenilemeyi denedi, o da reddedildi ve istemci oturumu kapalı
işaretledi. Yani **oturumun bittiğini istemciye söyleyen şey yenilemenin başarısız
olmasıdır.**

Bu düzeneğin bir yan etkisi vardır: ağ kopması yüzünden kaçırılan bir yenileme yanıtı da
oturumu düşürür. Kabul edilen bir ödünleşimdir; alternatifi, kullanılmış bir belirtecin bir
süre daha geçerli sayılmasıdır ki bu, saptamanın değerini azaltır.

## Döngü ve Kuyruk Tuzakları

Yenileme kodu iki tuzağa açıktır ve ikisi de üretimde görülür.

**Sonsuz döngü.** Yenileme isteğinin kendisi 401 döndürürse ve o istek de aynı yenileme
düzeneğinden geçiyorsa, döngü kapanmaz. Kural: yenileme isteği **kesinlikle** yenileme
düzeneğinden geçmez ve kendi 401'inde yeniden denenmez. Yukarıdaki kodda yenileme çağrısı
`istek` işlevini kullanmıyor, doğrudan gönderiliyor.

**Tek yineleme sınırı.** Yenilendikten sonra yinelenen istek yine 401 alırsa ikinci bir
yenileme denenmez. Bu durum, kullanıcının o kaynağa gerçekten yetkisi olmadığını gösterir;
yetki hatasını kimlik hatası sanıp yenilemeye devam etmek, oturumu boş yere yıpratır.

Bir de kuyruk kararı vardır. Yenileme sürerken gelen yeni istekler iki biçimde ele
alınabilir: eski belirteçle gönderilip 401 alarak kuyruğa katılmak, ya da yenileme bitene
kadar hiç gönderilmemek. İkincisi gereksiz istek üretmez ama uygulamanın her isteği
kimlik durumundan haberdar bir kapıdan geçirmesini gerektirir. Yukarıdaki kod birinciyi
uyguluyor; dört isteğin dördü de gitti, 401 aldı, tek yenilemede toplandı.

## Çıkış Akışı

Çıkış üç adımdan oluşur ve üçü de gereklidir.

**Sunucuda geçersizleştirme.** Çerez tabanlı bir düzende oturum kaydı silinir ve çerez boş
bir değerle, geçmiş bir son kullanma tarihiyle yeniden yazılır. Belirteç tabanlı bir
düzende yenileme belirteci iptal edilir. Yalnız istemci tarafını temizlemek çıkış değildir;
belirtecin bir kopyası hâlâ geçerli kalır.

**İstemci durumunun temizlenmesi.** Bellekteki belirteç, kimlik durumu ve **önbellekteki
kullanıcıya özel veriler** silinir. Sonuncusu sıkça atlanır: ölçüm geçmişi önbellekte
kalırsa, aynı tarayıcıda oturum açan ikinci bir gözlemci bir önceki kullanıcının verisini
bir an için görür. Veri Erişimi konusundaki normalleştirilmiş depo bu temizliğin hedefidir.

**Sekmeler arası eşitleme.** Aynı kullanıcı uygulamayı üç sekmede açmış olabilir. Bir
sekmede yapılan çıkış diğerlerine bildirilmezse, o sekmeler oturum açıkmış gibi davranmaya
devam eder ve ilk isteklerinde beklenmedik biçimde 401 alır. Bildirim, aynı kaynağın
sekmeleri arasında ileti geçişiyle ya da paylaşılan depolamadaki bir değişikliğin
izlenmesiyle yapılır; ikisi de Tarayıcı ve Web Platformu kursunda tanıtıldı. Aynı düzenek
ters yönde de çalışır: bir sekmede açılan oturum diğerlerinde de açılmış sayılır.

Çıkışın kullanıcı tarafındaki karşılığı da düşünülmelidir. Yarım kalmış bir formun içeriği
çıkışta silinir; kullanıcıya bunun sorulması, sessizce silmekten iyidir. Zorunlu çıkışta —
oturum düştüğünde — kullanıcı giriş ekranına yönlendirilirken bulunduğu adres saklanır ve
giriş sonrası oraya dönülür.

## Özet

- Yenilemenin üç tetikleyicisi vardır: 401 sonrası tepkisel, süre dolmadan önden ve sayfa
  açılışında sessiz oturum kurma. Önden yenileme tepkiselin yerine geçmez.
- Eşzamanlı yetki hataları tek uçuşlu bir yenilemede toplanır; uçuştaki söz ile kullanılan
  belirtecin karşılaştırılması birlikte gerekir.
- Yinelenen istek, yenileme sırasında değişmiş belirteci okumalıdır; isteğin başında
  yakalanan değer artık geçersizdir.
- Yenileme belirteci her kullanımda dönüşür; kullanılmış bir belirtecin ikinci kez gelmesi
  oturumun tümünün iptaliyle sonuçlanır.
- Yenileme isteği yenileme düzeneğinden geçmez ve yinelenen istek ikinci kez 401 alırsa
  yeniden yenilenmez.
- Çıkış sunucuda geçersizleştirme, istemci durumu ile kullanıcıya özel önbelleğin
  temizlenmesi ve sekmeler arası eşitleme adımlarının üçünü birden gerektirir.

## Sonraki Adım

Kimlik akışı tamamlandı: gözlemci tanınıyor, oturumu kendiliğinden sürüyor, çıkışı her
yerde etkili oluyor. Ama tanınan gözlemcinin bir de dili var. Bu kurs boyunca üretilen her
metin — hata iletileri, "oturum düştü" bildirimi, boş sonuç açıklamaları, tarih ve sayı
biçimleri — tek bir dile göre yazıldı. İstasyonu Norveç'ten izleyen bir gözlemci için
"−4,2" doğru biçim değildir, "2 alan düzeltilmeli" doğru cümle değildir ve arayüzün akış
yönü bile farklı olabilir. Son ders bu uyarlamayı kurar.
