Angular HttpClient ve Interceptor'lar 2026: HTTP İstek Yönetimi ve Mülakat Soruları

Angular 20 fonksiyonel interceptor'larına kapsamlı bir rehber: kimlik doğrulama token enjeksiyonundan üstel geri çekilme ile yeniden deneme mantığına kadar. Mülakat soruları ve production kalıpları içerir.

Angular HttpClient ve Interceptor'lar 2026: HTTP İstek Yönetimi ve Mülakat Soruları

Angular HttpClient interceptor'ları, uygulamaların HTTP isteklerini nasıl işlediğini dönüştürür — kimlik doğrulama başlıkları eklemekten yeniden deneme mantığı uygulamaya kadar. Angular 20, fonksiyonel interceptor'ları önerilen yaklaşım olarak standartlaştırdı ve eski sınıf tabanlı kalıbı daha öngörülebilir ve tree-shakeable bir API ile değiştirdi.

Fonksiyonel Interceptor'lar Standarttır

Angular 20, sınıf tabanlı interceptor'lar yerine withInterceptors() ile fonksiyonel interceptor'ları önerir. Fonksiyonel interceptor'lar daha öngörülebilir yürütme sırasına sahiptir ve standalone component'lerle daha iyi entegre olur.

provideHttpClient ile HttpClient Kurulumu

Interceptor'lar yazmadan önce, uygulama bootstrap'inde HttpClient yapılandırılmalıdır. Angular'ın standalone mimarisi, eski HttpClientModule yerine provideHttpClient() kullanır.

Kurulum, uygulama yapılandırmasında gerçekleşir:

main.tstypescript
import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { AppComponent } from './app/app.component';
import { authInterceptor } from './interceptors/auth.interceptor';
import { loggingInterceptor } from './interceptors/logging.interceptor';

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(
      // Interceptor'lar dizi sırasına göre çalışır
      withInterceptors([authInterceptor, loggingInterceptor])
    ),
  ],
});

Interceptor'lar dizide belirtilen sırayla çalışır. İlk interceptor giden isteği ilk işler ve son interceptor yanıtı ilk görür.

Fonksiyonel Interceptor Anatomisi

Fonksiyonel bir interceptor, isteği ve bir next fonksiyonunu alır. next(req) çağrısı, isteği zincirdeki bir sonraki interceptor'a veya bu son interceptor'sa backend'e iletir.

Temel yapı şöyle görünür:

interceptors/logging.interceptor.tstypescript
import { HttpInterceptorFn, HttpRequest, HttpHandlerFn, HttpEvent } from '@angular/common/http';
import { Observable, tap } from 'rxjs';

export const loggingInterceptor: HttpInterceptorFn = (
  req: HttpRequest<unknown>,
  next: HttpHandlerFn
): Observable<HttpEvent<unknown>> => {
  const startTime = performance.now();
  console.log(`[HTTP] ${req.method} ${req.url}`);

  return next(req).pipe(
    tap({
      next: () => {
        const duration = Math.round(performance.now() - startTime);
        console.log(`[HTTP] ${req.method} ${req.url} completed in ${duration}ms`);
      },
      error: (err) => {
        console.error(`[HTTP] ${req.method} ${req.url} failed:`, err.message);
      },
    })
  );
};

Interceptor, istek metodunu ve URL'yi loglar, ardından yanıt süresini ölçer. tap operatörü, yanıtı değiştirmeden gözlemler.

Token Enjeksiyonlu Kimlik Doğrulama Interceptor'ı

Çoğu uygulama, giden isteklere kimlik doğrulama token'ları eklemeyi gerektirir. Interceptor, HttpRequest nesneleri değiştirilemez olduğundan, isteği Authorization başlığıyla klonlar.

Bu kalıp, token'ı bir servisten alır ve ekler:

interceptors/auth.interceptor.tstypescript
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { AuthService } from '../services/auth.service';

export const authInterceptor: HttpInterceptorFn = (req, next) => {
  // Angular'ın inject() fonksiyonunu kullanarak servis enjeksiyonu
  const authService = inject(AuthService);
  const token = authService.getAccessToken();

  // Public endpoint'ler için auth başlığını atla
  if (req.url.includes('/public/') || !token) {
    return next(req);
  }

  // Authorization başlığıyla isteği klonla
  const authReq = req.clone({
    setHeaders: {
      Authorization: `Bearer ${token}`,
    },
  });

  return next(authReq);
};

inject() fonksiyonu çalışır çünkü interceptor'lar Angular'ın enjeksiyon bağlamında çalışır. Bu, sınıf tabanlı interceptor'lardaki constructor enjeksiyonu şablonunu ortadan kaldırır.

Hata Yönetimi ve Yeniden Deneme Mantığı

Ağ hataları olur. Yeniden deneme interceptor'ı, başarısız istekleri üstel geri çekilme ile otomatik olarak yeniden deneyebilir ve her HTTP çağrısında değişiklik gerektirmeden güvenilirliği artırır.

RxJS operatörleri yeniden deneme mantığını yönetir:

interceptors/retry.interceptor.tstypescript
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
import { retry, timer } from 'rxjs';

export const retryInterceptor: HttpInterceptorFn = (req, next) => {
  // Yalnızca GET isteklerini yeniden dene (idempotent)
  if (req.method !== 'GET') {
    return next(req);
  }

  return next(req).pipe(
    retry({
      count: 3,
      delay: (error: HttpErrorResponse, retryCount: number) => {
        // İstemci hatalarını yeniden deneme (4xx)
        if (error.status >= 400 && error.status < 500) {
          throw error;
        }
        // Üstel geri çekilme: 1s, 2s, 4s
        const delayMs = Math.pow(2, retryCount - 1) * 1000;
        console.log(`Yeniden deneme #${retryCount} - ${delayMs}ms sonra`);
        return timer(delayMs);
      },
    })
  );
};

Interceptor yalnızca GET isteklerini yeniden dener çünkü POST, PUT ve DELETE idempotent değildir. İstemci hataları (4xx), sunucu isteği açıkça reddettiği için yeniden denemeleri atlar.

Angular mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

HttpContext ile Yanıt Önbellekleme

HttpClient, interceptor'lar ve çağıran kod arasında meta veri geçirmek için HttpContext sağlar. Önbellekleme interceptor'ı, önbellek davranışını belirlemek için context token'larını okuyabilir.

Önbellek token'ı ve interceptor birlikte çalışır:

interceptors/cache.interceptor.tstypescript
import { HttpInterceptorFn, HttpContextToken, HttpResponse } from '@angular/common/http';
import { of, tap } from 'rxjs';

// İstek başına önbelleklemeyi kontrol etmek için context token'ı
export const CACHE_REQUEST = new HttpContextToken<boolean>(() => false);

const cache = new Map<string, HttpResponse<unknown>>();

export const cacheInterceptor: HttpInterceptorFn = (req, next) => {
  // Yalnızca context aracılığıyla açıkça istendiğinde önbellekle
  if (!req.context.get(CACHE_REQUEST) || req.method !== 'GET') {
    return next(req);
  }

  const cacheKey = req.urlWithParams;
  const cachedResponse = cache.get(cacheKey);

  if (cachedResponse) {
    console.log(`[Cache] HIT: ${cacheKey}`);
    return of(cachedResponse.clone());
  }

  return next(req).pipe(
    tap((event) => {
      if (event instanceof HttpResponse) {
        console.log(`[Cache] STORE: ${cacheKey}`);
        cache.set(cacheKey, event.clone());
      }
    })
  );
};

Çağıran kod, context token'ı ile önbelleklemeyi etkinleştirir:

services/user.service.tstypescript
import { HttpClient, HttpContext } from '@angular/common/http';
import { CACHE_REQUEST } from '../interceptors/cache.interceptor';

export class UserService {
  constructor(private http: HttpClient) {}

  getUser(id: string) {
    return this.http.get(`/api/users/${id}`, {
      context: new HttpContext().set(CACHE_REQUEST, true),
    });
  }
}

Bu kalıp, önbellekleme davranışını global yapılandırmada gizlemek yerine çağrı noktasında açık tutar.

401 İşleme ile Token Yenileme

Erişim token'ları süresi dolduğunda, sunucu 401 yanıtı döndürür. Bir interceptor bunu yakalayabilir, token'ı yenileyebilir ve orijinal isteği şeffaf bir şekilde yeniden deneyebilir.

Yenileme mantığı birden fazla eşzamanlı isteği koordine eder:

interceptors/token-refresh.interceptor.tstypescript
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
import { inject } from '@angular/core';
import { catchError, switchMap, throwError, BehaviorSubject, filter, take } from 'rxjs';
import { AuthService } from '../services/auth.service';

let isRefreshing = false;
const refreshTokenSubject = new BehaviorSubject<string | null>(null);

export const tokenRefreshInterceptor: HttpInterceptorFn = (req, next) => {
  const authService = inject(AuthService);

  return next(req).pipe(
    catchError((error: HttpErrorResponse) => {
      if (error.status !== 401 || req.url.includes('/auth/refresh')) {
        return throwError(() => error);
      }

      if (isRefreshing) {
        // Yenilemenin tamamlanmasını bekle
        return refreshTokenSubject.pipe(
          filter((token) => token !== null),
          take(1),
          switchMap((token) => {
            const retryReq = req.clone({
              setHeaders: { Authorization: `Bearer ${token}` },
            });
            return next(retryReq);
          })
        );
      }

      isRefreshing = true;
      refreshTokenSubject.next(null);

      return authService.refreshToken().pipe(
        switchMap((response) => {
          isRefreshing = false;
          refreshTokenSubject.next(response.accessToken);
          const retryReq = req.clone({
            setHeaders: { Authorization: `Bearer ${response.accessToken}` },
          });
          return next(retryReq);
        }),
        catchError((refreshError) => {
          isRefreshing = false;
          authService.logout();
          return throwError(() => refreshError);
        })
      );
    })
  );
};

BehaviorSubject, birkaç istek aynı anda başarısız olduğunda birden fazla yenileme çağrısını önler. Token yenilendiğinde, kuyruktaki tüm istekler yeni token ile yeniden denenir.

Mülakat Soruları: HttpClient ve Interceptor'lar

Teknik mülakatlar genellikle HTTP işleme kalıplarının anlaşılmasını araştırır. Bu sorular Angular pozisyonlarında sıkça karşılaşılır.

S: Fonksiyonel interceptor'lar neden sınıf tabanlı interceptor'lara tercih edilir?

Fonksiyonel interceptor'lar daha öngörülebilir yürütme sırasına sahiptir. Angular dokümantasyonu, withInterceptors() ile fonksiyonel interceptor'ların katı dizi sırasını koruduğunu, DI tabanlı interceptor'ların karmaşık modül hiyerarşilerinde sıralama sorunlarına sahip olabileceğini belirtir. Fonksiyonel interceptor'lar ayrıca daha iyi tree-shake oldukları için daha küçük bundle'lar üretir.

S: Belirli isteklerde interceptor'ın çalışmasını nasıl engellersiniz?

İki yaklaşım vardır. Birincisi, interceptor'da URL kalıbını kontrol etmek ve hariç tutulan yollar için değişiklik yapmadan next(req) çağırmak. İkincisi, çağıran kodun interceptor davranışından çıkmak için ayarladığı HttpContext token'larını kullanmak. Context yaklaşımı, hariç tutma kararını çağrı noktasında tutar.

S: Interceptor'da next() çağırmayı unutursanız ne olur?

İstek asla sunucuya ulaşmaz. next() tarafından döndürülen Observable, interceptor zincirinin geri kalanını ve gerçek HTTP çağrısını temsil eder. Çağrılmadan, downstream interceptor'lar ve backend isteği asla görmez. Bu, önbellekten yanıt döndüren önbellekleme interceptor'ları için kasıtlıdır.

S: Token yenileme sırasında eşzamanlı istekleri nasıl yönetirsiniz?

Koordinasyon için BehaviorSubject kullanın. İlk 401 yenilemeyi tetiklediğinde, bir bayrak ayarlayın ve subject'e null emit edin. Sonraki 401'ler, yeni token gelene kadar filter ile subject'i bekler. Bu, birden fazla yenileme çağrısını önler ve tüm bekleyen isteklerin aynı taze token ile yeniden denemesini sağlar.

S: Interceptor'lar yanıt gövdesini değiştirebilir mi?

Evet. HttpResponse nesnelerini dönüştürmek için next() tarafından döndürülen Observable'da map() kullanın. Yanıtlar değiştirilemez olduğundan, değiştirilmiş gövdelerle klonlayın. Bu kalıp, hesaplanmış alanlar eklemek, API zarflarını açmak veya veri yapılarını normalize etmek için çalışır.

Daha fazla Angular mülakat hazırlığı için HttpClient mülakat soruları modülüne bakın.

Fonksiyonel Interceptor'ları Test Etme

Interceptor'lar, mock edilmiş HTTP handler'larla test edilmelidir. Angular'ın HttpTestingController'ı, provideHttpClient() aracılığıyla kaydedilen interceptor'larla çalışır.

Bir test kurulumu şöyle görünür:

interceptors/auth.interceptor.spec.tstypescript
import { TestBed } from '@angular/core/testing';
import { HttpClient, provideHttpClient, withInterceptors } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { authInterceptor } from './auth.interceptor';
import { AuthService } from '../services/auth.service';

describe('authInterceptor', () => {
  let httpClient: HttpClient;
  let httpTesting: HttpTestingController;
  let authServiceSpy: jasmine.SpyObj<AuthService>;

  beforeEach(() => {
    authServiceSpy = jasmine.createSpyObj('AuthService', ['getAccessToken']);

    TestBed.configureTestingModule({
      providers: [
        provideHttpClient(withInterceptors([authInterceptor])),
        provideHttpClientTesting(),
        { provide: AuthService, useValue: authServiceSpy },
      ],
    });

    httpClient = TestBed.inject(HttpClient);
    httpTesting = TestBed.inject(HttpTestingController);
  });

  it('should add Authorization header when token exists', () => {
    authServiceSpy.getAccessToken.and.returnValue('test-token');

    httpClient.get('/api/data').subscribe();

    const req = httpTesting.expectOne('/api/data');
    expect(req.request.headers.get('Authorization')).toBe('Bearer test-token');
    req.flush({ data: 'test' });
  });

  it('should skip Authorization for public endpoints', () => {
    authServiceSpy.getAccessToken.and.returnValue('test-token');

    httpClient.get('/public/health').subscribe();

    const req = httpTesting.expectOne('/public/health');
    expect(req.request.headers.has('Authorization')).toBeFalse();
    req.flush({ status: 'ok' });
  });
});

Test, gerçek ağ istekleri yapmadan hem başlık enjeksiyonunu hem de public endpoint istisnasını doğrular.

Production Kalıpları: Interceptor'ları Birleştirme

Gerçek uygulamalar birden fazla interceptor'ı yığınlar. Sıra önemlidir: kimlik doğrulama loglama'dan önce, önbellekleme yeniden deneme mantığından önce olmalıdır.

Bir production yapılandırması şöyle görünebilir:

main.tstypescript
import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { AppComponent } from './app/app.component';
import { authInterceptor } from './interceptors/auth.interceptor';
import { tokenRefreshInterceptor } from './interceptors/token-refresh.interceptor';
import { cacheInterceptor } from './interceptors/cache.interceptor';
import { retryInterceptor } from './interceptors/retry.interceptor';
import { loggingInterceptor } from './interceptors/logging.interceptor';

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(
      withInterceptors([
        // Sıra: auth -> refresh -> cache -> retry -> logging
        authInterceptor,
        tokenRefreshInterceptor,
        cacheInterceptor,
        retryInterceptor,
        loggingInterceptor,
      ])
    ),
  ],
});

Bu sıralama, token'ların yenileme işleminden önce eklenmesini, önbellek kontrollerinin yeniden denemelerden önce gerçekleşmesini ve loglama'nın son zamanlamayı kaydetmesini sağlar.

Daha fazla Angular kalıbı için, interceptor'larda kullanılan operatörleri kapsayan RxJS temelleri modülüne bakın.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Angular HttpClient Interceptor'ları için Temel Çıkarımlar

  • withInterceptors() ile fonksiyonel interceptor'lar Angular 20 standardıdır, sınıf tabanlı alternatiflere göre öngörülebilir sıralama ve daha iyi tree-shaking sunar
  • Constructor şablonu olmadan servislere erişmek için interceptor'ların içinde inject() kullanın
  • HttpRequest nesneleri değiştirilemez olduğundan başlıkları değiştirmek için req.clone() ile istekleri klonlayın
  • HttpContext token'ları, istek başına davranışı global yapılandırmada gizlemek yerine çağrı noktasında açık yapar
  • Token yenileme interceptor'ları, birden fazla yenileme çağrısını önlemek için BehaviorSubject ile eşzamanlı istekleri koordine etmelidir
  • Interceptor sırası önemlidir: kimlik doğrulama önbelleklemeden önce, önbellekleme yeniden denemeden önce, loglama en sonda
Günün meydan okuması

Angular kodundaki hatayı bulabilir misin?

Gerçek bir kod parçası, gizli bir hata, günde bir deneme. Denemek için hesap gerekmez.

Anthony Fillion-Maillet

Yazan:

Anthony Fillion-Maillet

SharpSkill kurucusu

10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.

22 Ağustos 2026 tarihinde güncellendi

Paylaş

İlgili makaleler