Angular SSR’da “Kimliği Doğrulanmış İçeriğin Anlık Görünümü” (Flash of Authenticated Content) Sorununu Yönetmek
Angular Sunucu Tarafı Oluşturma (SSR), uygulamaların ilk yükleme performansını ve SEO değerini artırmak için güçlü bir araçtır. Ancak, SSR ile kimlik doğrulama süreçlerini birleştirdiğinizde, “Flash of Authenticated Content” (FOAC) olarak bilinen yaygın bir sorunla karşılaşabilirsiniz. Bu durum, kullanıcının kısa bir süre için kimliği doğrulanmamış içeriği görmesi ve ardından aniden kimliği doğrulanmış içeriğin yüklenmesiyle ortaya çıkan rahatsız edici bir görsel geçiştir. Bu makalede, FOAC’ın nedenlerini, etkilerini ve Angular SSR uygulamalarınızda bu sorunu etkili bir şekilde nasıl yöneteceğinizi detaylıca inceleyeceğiz.
“Flash of Authenticated Content” (FOAC) Nedir ve Neden Ortaya Çıkar?
“Flash of Authenticated Content” (FOAC), kullanıcıların bir web sayfasını ziyaret ettiğinde, sunucudan gelen ilk HTML çıktısında kimliği doğrulanmamış bir görünümle karşılaşması, ardından tarayıcıda Angular uygulamasının tam olarak yüklendiğinde ve kimlik doğrulama durumu kontrol edildiğinde kimliği doğrulanmış içeriğin aniden belirmesi durumudur. Bu, kullanıcı deneyimini olumsuz etkileyen, profesyonel olmayan bir görünüm yaratır.
SSR ve Kimlik Doğrulama Mekanizması
Angular SSR, sunucuda uygulamanın ilk HTML çıktısını oluşturarak tarayıcıya gönderir. Bu süreç, uygulamanın JavaScript’inin tarayıcıda çalışmaya başlamasından önce gerçekleşir. Kimlik doğrulama genellikle istemci tarafında (tarayıcıda) depolanan çerezler veya yerel depolama (localStorage) aracılığıyla yönetilir. Sunucu, bu kimlik bilgilerine her zaman erişemeyebilir veya erişse bile, istemci tarafında kimlik doğrulama mekanizmalarının senkronize çalışmaması FOAC’a yol açabilir.
Tarayıcı ve Sunucu Farklılıkları
Sunucu ortamı ile tarayıcı ortamı arasında temel farklılıklar bulunur. Sunucu, genellikle kullanıcının çerezlerine doğrudan erişebilirken, localStorage veya sessionStorage gibi tarayıcıya özgü depolama mekanizmalarına erişemez. Eğer kimlik doğrulama durumu bu depolama alanlarında saklanıyorsa, sunucu ilk HTML çıktısını oluştururken kullanıcının kimlik doğrulama durumunu bilemez ve varsayılan olarak “misafir” veya “çıkış yapılmış” içeriği render eder.
Kullanıcı Deneyimi Üzerindeki Etkileri
FOAC, kullanıcılarda kafa karışıklığına, güven eksikliğine ve uygulamanın yavaş veya hatalı çalıştığı izlenimine neden olabilir. Özellikle hassas bilgilerin veya kişiselleştirilmiş içeriğin gösterildiği uygulamalarda, bu anlık geçiş profesyonel olmayan bir izlenim bırakır ve kullanıcı sadakatini azaltabilir.
FOAC’ı Tetikleyen Temel Senaryolar
FOAC’ın ortaya çıkışını anlamak, onu çözmek için atılacak adımların temelini oluşturur. Genellikle birkaç farklı senaryo bu duruma yol açar.
Sunucuda Kimlik Bilgisinin Olmaması
En yaygın senaryo, sunucu tarafında render edilirken kullanıcının kimlik doğrulama durumunun bilinememesidir. Örneğin, eğer bir kullanıcı çerez yerine localStorage‘da bir JWT tokenı saklıyorsa, sunucu bu tokene erişemeyeceği için kullanıcının oturum açmış olup olmadığını anlayamaz. Bu durumda sunucu, genel (kimliği doğrulanmamış) içeriği render eder. Tarayıcıda Angular uygulaması yüklendiğinde, localStorage‘dan token okunur, kimlik doğrulaması yapılır ve içerik güncellenir, bu da FOAC’a neden olur.
Asenkron Kimlik Doğrulama Kontrolleri
Bazı uygulamalar, kimlik doğrulama durumunu kontrol etmek için bir API çağrısı yapar. Eğer bu API çağrısı sunucu tarafında render işlemi sırasında yapılmazsa veya tamamlanmazsa, sunucu yine kimliği doğrulanmamış içeriği render eder. Tarayıcıda uygulama başlatıldığında, API çağrısı yapılır, yanıt gelir ve içerik değişir. Bu asenkron yapı, FOAC’ın ortaya çıkışını hızlandırabilir veya daha belirgin hale getirebilir.
Veri Getirme ve Durum Yönetimi
Kimliği doğrulanmış kullanıcılar için özel veriler (örneğin, kullanıcı profili bilgileri, sipariş geçmişi) genellikle bir API üzerinden getirilir. Eğer bu veri getirme işlemi sunucuda kimlik doğrulama durumuna bağlı olarak yapılmazsa, sunucu genel bir görünüm oluşturur. Tarayıcıda, kimlik doğrulama başarılı olduktan sonra bu veriler getirilir ve arayüz güncellenir. Bu da FOAC’a katkıda bulunur.
FOAC’ı Azaltmaya Yönelik Temel Stratejiler
FOAC sorununu tamamen ortadan kaldırmak veya etkilerini en aza indirmek için çeşitli stratejiler mevcuttur. Bu stratejiler, sunucu ve istemci tarafı arasındaki senkronizasyonu iyileştirmeyi hedefler.
Sunucuda Kimlik Doğrulama Durumunu Önceden Belirleme
En etkili yaklaşımlardan biri, sunucunun render işlemi sırasında kullanıcının kimlik doğrulama durumunu bilmesini sağlamaktır. Bu genellikle HTTP çerezleri aracılığıyla yapılır. Eğer kimlik doğrulama tokenı bir HTTP Only çerezi olarak saklanıyorsa, sunucu bu çereze erişebilir ve kullanıcının oturum açmış olup olmadığını anlayarak buna göre ilk HTML çıktısını oluşturabilir.
Durum Aktarımı (State Transfer) Kullanımı
Angular Universal’ın sunduğu TransferState mekanizması, sunucu tarafında oluşturulan herhangi bir veriyi istemci tarafına güvenli ve verimli bir şekilde aktarmak için tasarlanmıştır. Bu, sunucuda yapılan kimlik doğrulama kontrollerinin sonucunu veya kullanıcıya özel verileri istemciye taşıyarak, istemcinin aynı kontrolleri tekrar yapmasını engeller ve FOAC’ı önler.
İstemci Tarafında Gecikmeli Render (Delayed Rendering)
Bazı durumlarda, özellikle kimlik doğrulama durumu karmaşık veya asenkron bir süreç gerektiriyorsa, istemci tarafında belirli UI bileşenlerinin render edilmesini geciktirmek bir çözüm olabilir. Bu, kimlik doğrulama durumunun kesinleştiğinden emin olana kadar hassas içeriği gizleyerek, anlık geçişin etkisini azaltır.
Angular SSR’da Durum Aktarımını Etkin Kullanma
Angular’ın TransferState modülü, FOAC sorununu çözmek için güçlü bir araçtır. Sunucuda elde edilen verileri istemciye taşıyarak, istemcinin aynı verileri tekrar getirmesini veya aynı kontrolleri yapmasını engeller.
TransferState Modülü ve Kullanımı
TransferState, Angular Universal’ın bir parçasıdır. Sunucuda verileri bir anahtar-değer çifti olarak saklamanıza ve bu verileri istemci tarafında geri yüklemenize olanak tanır.
Kullanımı için öncelikle BrowserTransferStateModule ve ServerTransferStateModule‘ü ilgili modüllerinize (genellikle AppBrowserModule ve AppServerModule) eklemeniz gerekir.
// app.server.module.ts
import { ServerModule, ServerTransferStateModule } from '@angular/platform-server';
// ...
@NgModule({
imports: [
AppModule,
ServerModule,
ServerTransferStateModule, // Sunucuda durum aktarımını etkinleştirir
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
// app.browser.module.ts
import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser';
// ...
@NgModule({
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
BrowserTransferStateModule, // Tarayıcıda durum aktarımını etkinleştirir
],
providers: [],
bootstrap: [AppComponent],
})
export class AppBrowserModule {}
Sunucuda Kimlik Bilgisini Saklama
Sunucu tarafında, kimlik doğrulama durumunu veya kullanıcı verilerini TransferState'e kaydedebilirsiniz. Bu genellikle bir servis içinde veya bir resolver'da yapılır.
// auth.service.ts (Sunucu tarafı)
import { Injectable, PLATFORM_ID, Inject } from '@angular/core';
import { isPlatformServer } from '@angular/common';
import { TransferState, makeStateKey } from '@angular/platform-browser';
import { Request } from 'express'; // Express Request objesi için
const AUTH_STATE_KEY = makeStateKey('isAuthenticated');
const USER_DATA_KEY = makeStateKey('userData');
@Injectable({
providedIn: 'root'
})
export class AuthService {
private isAuthenticated = false;
private userData: any = null;
constructor(
private transferState: TransferState,
@Inject(PLATFORM_ID) private platformId: Object,
@Inject('REQUEST') private request: Request // Express Request objesini enjekte ediyoruz
) {
if (isPlatformServer(this.platformId)) {
// Sunucu tarafında kimlik doğrulama kontrolü yap
// Örneğin, çerezlerden token oku
const token = this.request.cookies['auth_token']; // Express middleware ile gelen çerezler
if (token) {
// Token'ı doğrula ve kullanıcı verilerini al
// Bu kısım gerçek bir API çağrısı veya JWT doğrulama olabilir
this.isAuthenticated = true;
this.userData = { name: 'Kullanıcı Adı', email: 'kullanici@example.com' }; // Örnek veri
// Durumu TransferState'e kaydet
this.transferState.set(AUTH_STATE_KEY, this.isAuthenticated);
this.transferState.set(USER_DATA_KEY, this.userData);
}
}
}
getAuthStatus(): boolean {
return this.isAuthenticated;
}
getUserData(): any {
return this.userData;
}
}
İstemcide Kimlik Bilgisini Geri Yükleme
İstemci tarafında, TransferState'den daha önce kaydedilen verileri okuyarak kimlik doğrulama durumunu veya kullanıcı verilerini hızlıca geri yükleyebilirsiniz. Bu sayede, istemci tarafında tekrar API çağrısı yapmaya veya çerezleri kontrol etmeye gerek kalmaz.
// auth.service.ts (İstemci tarafı)
import { Injectable, PLATFORM_ID, Inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { TransferState, makeStateKey } from '@angular/platform-browser';
const AUTH_STATE_KEY = makeStateKey('isAuthenticated');
const USER_DATA_KEY = makeStateKey('userData');
@Injectable({
providedIn: 'root'
})
export class AuthService {
private _isAuthenticated: boolean;
private _userData: any;
constructor(
private transferState: TransferState,
@Inject(PLATFORM_ID) private platformId: Object
) {
if (isPlatformBrowser(this.platformId)) {
// Tarayıcı tarafında TransferState'den durumu geri yükle
this._isAuthenticated = this.transferState.get(AUTH_STATE_KEY, false);
this._userData = this.transferState.get(USER_DATA_KEY, null);
// TransferState'den okuduktan sonra anahtarları silmek iyi bir uygulamadır
this.transferState.delete(AUTH_STATE_KEY);
this.transferState.delete(USER_DATA_KEY);
}
}
isAuthenticated(): boolean {
return this._isAuthenticated;
}
getUserData(): any {
return this._userData;
}
// ... Diğer kimlik doğrulama metotları (login, logout vb.)
}
Bu örnekte, AuthService hem sunucuda hem de istemcide çalışacak şekilde tasarlanmıştır. Sunucuda kimlik durumunu belirleyip TransferState'e yazar, istemcide ise bu durumu TransferState'den okur.
Görsel Çözümler ve Kullanıcı Deneyimi İyileştirmeleri
TransferState gibi teknik çözümler FOAC'ı büyük ölçüde ortadan kaldırsa da, bazı durumlarda görsel geçişleri tamamen engellemek mümkün olmayabilir. Bu gibi durumlarda, kullanıcı deneyimini iyileştirmek için görsel stratejiler devreye girer.
Placeholder ve Yükleme İskeletleri (Skeleton Loaders)
Kimlik doğrulama durumunun veya kullanıcıya özel verilerin yüklenmesi zaman alabilir. Bu süre zarfında boş bir sayfa göstermek yerine, içeriğin geleceğini belirten placeholder'lar veya iskelet yükleyiciler kullanmak kullanıcıya daha iyi bir deneyim sunar. Bu, içeriğin yüklenmekte olduğunu görsel olarak belirtir ve anlık geçişin şokunu azaltır.
Hoş Geldiniz, {{ authService.getUserData()?.name }}
Bu sizin kişiselleştirilmiş içeriğiniz.
Giriş Yapın
Kişiselleştirilmiş içeriği görmek için lütfen giriş yapın.
CSS ile İçerik Gizleme
Bazı durumlarda, kimliği doğrulanmış içeriği başlangıçta tamamen gizlemek ve yalnızca kimlik doğrulama durumu kesinleştikten sonra görünür hale getirmek tercih edilebilir. Bu, özellikle FOAC'ın görsel etkisinin çok rahatsız edici olduğu durumlarda kullanılır.
Hoş Geldiniz, {{ authService.getUserData()?.name }}
Bu sizin kişiselleştirilmiş içeriğiniz.
Giriş Yapın
Kişiselleştirilmiş içeriği görmek için lütfen giriş yapın.
Bu yaklaşım, istemci tarafında kimlik doğrulama durumu netleşene kadar bir içeriğin görünmesini engeller. Ancak, sunucudan gelen HTML'de bu içerik yine de yer alacağı için SEO açısından dikkatli olunmalıdır.
Kullanıcıyı Bilgilendirme Mesajları
Eğer FOAC kaçınılmazsa, kullanıcıya bir bilgilendirme mesajı göstermek, uygulamanın durumunu anlamalarına yardımcı olabilir. "Kullanıcı bilgileriniz yükleniyor..." gibi basit bir mesaj, geçişin nedenini açıklayarak kullanıcı deneyimini yumuşatabilir.
Gelişmiş Stratejiler ve Dikkat Edilmesi Gerekenler
FOAC'ı yönetirken daha karmaşık senaryolar ve güvenlik/performans konuları da göz önünde bulundurulmalıdır.
JWT ve Çerez Yönetimi
JWT (JSON Web Token) kullanırken, token'ı HTTP Only çerezlerinde saklamak, sunucunun token'a güvenli bir şekilde erişmesini sağlar ve FOAC'ı önlemek için önemlidir. localStorage veya sessionStorage kullanıldığında sunucu erişimi mümkün olmadığından, bu depolama yöntemleri SSR senaryolarında FOAC riskini artırır.
Sunucu Tarafında Yönlendirmeler
Eğer bir sayfa yalnızca kimliği doğrulanmış kullanıcılar içinse ve sunucu kullanıcının kimliği doğrulanmadığını tespit ederse, doğrudan sunucu tarafında bir giriş sayfasına veya genel bir sayfaya yönlendirme yapmak FOAC'ı tamamen engelleyebilir. Bu, kullanıcının yanlış içeriği görmesini baştan önler.
// server.ts (Express sunucu tarafı)
app.get('*', (req, res) => {
const token = req.cookies['auth_token'];
const isAuthPage = req.url.startsWith('/login') || req.url.startsWith('/register');
if (!token && !isAuthPage && req.url.startsWith('/app/private')) { // Örnek: "/app/private" ile başlayan sayfalar korumalı
res.redirect('/login'); // Sunucu tarafında yönlendirme
return;
}
res.render(indexHtml, { req, providers: [{ provide: 'REQUEST', useValue: req }] });
});
Güvenlik Konuları
TransferState ile hassas bilgileri aktarırken dikkatli olunmalıdır. TransferState içindeki veriler, tarayıcıda sayfa kaynağında görünür olacaktır. Bu nedenle, parolalar veya diğer çok gizli bilgiler doğrudan TransferState üzerinden aktarılmamalıdır. Yalnızca kimlik doğrulama durumu (true/false) veya temel, güvenli kullanıcı profili bilgileri gibi veriler aktarılmalıdır.
Performans Etkileri
Sunucuda daha fazla işlem yapmak (çerezleri kontrol etmek, token'ı doğrulamak, API çağrıları yapmak) sunucu yanıt süresini artırabilir. Bu nedenle, FOAC'ı önlemeye yönelik stratejilerin performans üzerindeki etkileri dengeli bir şekilde değerlendirilmelidir. TransferState kullanmak, istemci tarafında tekrar API çağrısı yapma ihtiyacını ortadan kaldırarak toplam performansı genellikle iyileştirir.
Sonuç
"Flash of Authenticated Content", Angular SSR uygulamalarında karşılaşılan yaygın ancak yönetilebilir bir sorundur. TransferState gibi Angular Universal'ın sağladığı araçları etkin bir şekilde kullanarak, sunucu ve istemci arasındaki kimlik doğrulama durumunu senkronize edebilir ve bu görsel rahatsızlığı büyük ölçüde ortadan kaldırabilirsiniz. Ayrıca, iskelet yükleyiciler ve CSS tabanlı gizleme teknikleri gibi görsel çözümlerle kullanıcı deneyimini daha da iyileştirebilirsiniz. Doğru stratejilerle, hem SEO avantajlarından yararlanan hızlı ve performanslı bir SSR uygulaması sunabilir hem de kullanıcılara kesintisiz ve profesyonel bir deneyim sağlayabilirsiniz.
SSS (Sık Sorulan Sorular)
FOAC sadece Angular SSR'da mı görülür?
Hayır, FOAC benzeri sorunlar React (Next.js), Vue (Nuxt.js) gibi diğer sunucu tarafı oluşturma framework'lerinde de görülebilir. Temel neden, sunucu ve istemci ortamları arasındaki farklılıklar ve kimlik doğrulama durumunun senkronizasyon eksikliğidir.
TransferState kullanmak performansı nasıl etkiler?
TransferState, sunucuda zaten getirilmiş olan verilerin istemci tarafında tekrar getirilmesini engelleyerek genellikle performansı iyileştirir. Bu, ağ isteklerini azaltır ve uygulamanın daha hızlı interaktif hale gelmesini sağlar. Ancak, çok büyük miktarda veriyi TransferState üzerinden aktarmak, ilk HTML çıktısının boyutunu artırabilir.
localStorage kullanarak kimlik doğrulaması yapıyorsam FOAC'ı nasıl önleyebilirim?
localStorage sunucu tarafında erişilebilir olmadığı için, sunucuda kimlik doğrulama durumunu belirleyemezsiniz. Bu durumda, FOAC'ı önlemek için genellikle görsel çözümler (iskelet yükleyiciler, CSS ile gizleme) veya sunucuda kimliği doğrulanmamış kullanıcılar için genel bir sayfa render edip, istemcide kimlik doğrulandıktan sonra yönlendirme yapmak gibi stratejiler izlenir. En iyi uygulama, SSR ile uyumlu olması için HTTP Only çerezlerini kullanmaktır.
FOAC, SEO üzerinde olumsuz bir etki yaratır mı?
Doğrudan bir SEO etkisi olmasa da, FOAC kötü bir kullanıcı deneyimine yol açtığı için dolaylı olarak SEO'yu etkileyebilir. Arama motorları kullanıcı deneyimini sıralama faktörlerinden biri olarak değerlendirir. Ayrıca, eğer kimliği doğrulanmış içerik başlangıçta gizleniyorsa ve arama motoru botları bu içeriği göremezse, bu da SEO açısından sorun yaratabilir. TransferState gibi çözümler, arama motorlarının doğru içeriği görmesini sağlayarak bu riski azaltır.
