Angular HttpClient en Interceptors in 2026: Request Handling en Sollicitatievragen
Uitgebreide handleiding voor Angular HttpClient interceptors: functionele interceptors, authenticatie, token refresh, caching en veelgestelde sollicitatievragen voor Angular-ontwikkelaars.

Angular HttpClient interceptors transformeren hoe applicaties HTTP-requests verwerken, van het toevoegen van authenticatie-headers tot het implementeren van retry-logica. Angular 20 heeft functionele interceptors gestandaardiseerd als de aanbevolen aanpak, waarmee het oudere class-based patroon wordt vervangen door een meer voorspelbare en tree-shakable API.
Angular 20 beveelt functionele interceptors aan met withInterceptors() boven class-based interceptors. Functionele interceptors hebben een meer voorspelbare uitvoeringsvolgorde en integreren beter met standalone componenten.
HttpClient Setup met provideHttpClient
Voordat interceptors geschreven kunnen worden, moet HttpClient geconfigureerd worden in de applicatie bootstrap. Angular's standalone architectuur gebruikt provideHttpClient() in plaats van de oudere HttpClientModule.
De setup vindt plaats in de applicatieconfiguratie:
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(
// Interceptors worden uitgevoerd in array-volgorde
withInterceptors([authInterceptor, loggingInterceptor])
),
],
});Interceptors worden uitgevoerd in de volgorde die in de array is opgegeven. De eerste interceptor verwerkt het uitgaande request eerst, en de laatste interceptor ziet de response eerst.
Anatomie van een Functionele Interceptor
Een functionele interceptor ontvangt het request en een next-functie. Het aanroepen van next(req) geeft het request door aan de volgende interceptor in de keten of aan de backend als dit de laatste interceptor is.
De basisstructuur ziet er als volgt uit:
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);
},
})
);
};De interceptor logt de request-methode en URL, en meet vervolgens de responstijd. De tap-operator observeert de response zonder deze te wijzigen.
Authenticatie Interceptor met Token Injectie
De meeste applicaties moeten authenticatie-tokens toevoegen aan uitgaande requests. De interceptor kloont het request met de Authorization-header, aangezien HttpRequest-objecten onveranderlijk zijn.
Dit patroon haalt het token op van een service en voegt het toe:
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { AuthService } from '../services/auth.service';
export const authInterceptor: HttpInterceptorFn = (req, next) => {
// Injecteer services met Angular's inject()-functie
const authService = inject(AuthService);
const token = authService.getAccessToken();
// Sla auth-header over voor publieke endpoints
if (req.url.includes('/public/') || !token) {
return next(req);
}
// Kloon request met Authorization-header
const authReq = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
},
});
return next(authReq);
};De inject()-functie werkt omdat interceptors worden uitgevoerd binnen Angular's injection-context. Dit elimineert de constructor-injection boilerplate van class-based interceptors.
Foutafhandeling en Retry-logica
Netwerkfouten komen voor. Een retry-interceptor kan automatisch mislukte requests opnieuw proberen met exponentiële backoff, wat de betrouwbaarheid verbetert zonder wijzigingen aan elke HTTP-aanroep te vereisen.
RxJS-operators verwerken de retry-logica:
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
import { retry, timer } from 'rxjs';
export const retryInterceptor: HttpInterceptorFn = (req, next) => {
// Alleen GET-requests opnieuw proberen (idempotent)
if (req.method !== 'GET') {
return next(req);
}
return next(req).pipe(
retry({
count: 3,
delay: (error: HttpErrorResponse, retryCount: number) => {
// Client-fouten (4xx) niet opnieuw proberen
if (error.status >= 400 && error.status < 500) {
throw error;
}
// Exponentiële backoff: 1s, 2s, 4s
const delayMs = Math.pow(2, retryCount - 1) * 1000;
console.log(`Retry #${retryCount} in ${delayMs}ms`);
return timer(delayMs);
},
})
);
};De interceptor probeert alleen GET-requests opnieuw omdat POST, PUT en DELETE niet idempotent zijn. Client-fouten (4xx) slaan retries over omdat de server het request expliciet heeft afgewezen.
Klaar om je Angular gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
Response Caching met HttpContext
HttpClient biedt HttpContext om metadata tussen interceptors en aanroepende code door te geven. Een caching-interceptor kan context-tokens lezen om het cache-gedrag te bepalen.
Het cache-token en de interceptor werken samen:
import { HttpInterceptorFn, HttpContextToken, HttpResponse } from '@angular/common/http';
import { of, tap } from 'rxjs';
// Context-token om caching per request te controleren
export const CACHE_REQUEST = new HttpContextToken<boolean>(() => false);
const cache = new Map<string, HttpResponse<unknown>>();
export const cacheInterceptor: HttpInterceptorFn = (req, next) => {
// Alleen cachen als expliciet aangevraagd via context
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());
}
})
);
};De aanroepende code kiest voor caching met het context-token:
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),
});
}
}Dit patroon houdt het caching-gedrag expliciet op de aanroepplek in plaats van verborgen in de globale configuratie.
Token Refresh met 401 Afhandeling
Wanneer access tokens verlopen, retourneert de server een 401-response. Een interceptor kan dit opvangen, het token vernieuwen en het oorspronkelijke request transparant opnieuw proberen.
De refresh-logica coordineert meerdere gelijktijdige requests:
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) {
// Wacht tot de refresh is voltooid
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);
})
);
})
);
};Het BehaviorSubject voorkomt meerdere refresh-aanroepen wanneer verschillende requests tegelijkertijd falen. Zodra het token is vernieuwd, proberen alle wachtende requests opnieuw met het nieuwe token.
Sollicitatievragen: HttpClient en Interceptors
Technische sollicitatiegesprekken testen vaak het begrip van HTTP-afhandelingspatronen. Deze vragen komen regelmatig voor bij Angular-posities.
V: Waarom hebben functionele interceptors de voorkeur boven class-based interceptors?
Functionele interceptors hebben een meer voorspelbare uitvoeringsvolgorde. De Angular-documentatie stelt dat functionele interceptors met withInterceptors() een strikte array-volgorde handhaven, terwijl DI-gebaseerde interceptors volgordeproblemen kunnen hebben in complexe module-hierarchieën. Functionele interceptors produceren ook kleinere bundles omdat ze beter tree-shaken.
V: Hoe voorkom je dat een interceptor wordt uitgevoerd op specifieke requests?
Er zijn twee benaderingen. Ten eerste, controleer het URL-patroon in de interceptor en roep next(req) aan zonder wijziging voor uitgesloten paden. Ten tweede, gebruik HttpContext-tokens die de aanroepende code instelt om af te zien van interceptor-gedrag. De context-benadering houdt de uitsluitingsbeslissing op de aanroepplek.
V: Wat gebeurt er als je vergeet next() aan te roepen in een interceptor?
Het request bereikt nooit de server. Het Observable dat door next() wordt geretourneerd, vertegenwoordigt de rest van de interceptor-keten en de daadwerkelijke HTTP-aanroep. Zonder dit aan te roepen, zien volgende interceptors en de backend het request nooit. Dit is opzettelijk voor caching-interceptors die gecachte responses retourneren.
V: Hoe ga je om met gelijktijdige requests tijdens token refresh?
Gebruik een BehaviorSubject om te coordineren. Wanneer de eerste 401 een refresh triggert, stel een flag in en emit null op het subject. Volgende 401's wachten op het subject met filter totdat het nieuwe token arriveert. Dit voorkomt meerdere refresh-aanroepen en zorgt ervoor dat alle wachtende requests opnieuw proberen met hetzelfde verse token.
V: Kunnen interceptors de response body wijzigen?
Ja. Gebruik map() op het Observable dat door next() wordt geretourneerd om HttpResponse-objecten te transformeren. Aangezien responses onveranderlijk zijn, kloon ze met gewijzigde bodies. Dit patroon werkt voor het toevoegen van berekende velden, het uitpakken van API-envelopes of het normaliseren van datastructuren.
Voor meer Angular sollicitatievoorbereiding, zie de HttpClient sollicitatievragen module.
Testen van Functionele Interceptors
Interceptors vereisen testen met gemockte HTTP-handlers. Angular's HttpTestingController werkt met interceptors die zijn geregistreerd via provideHttpClient().
Een test-setup ziet er als volgt uit:
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' });
});
});De test verifieert zowel de header-injectie als de uitzondering voor publieke endpoints zonder daadwerkelijke netwerkverzoeken te doen.
Productiepatronen: Combineren van Interceptors
Echte applicaties stapelen meerdere interceptors. De volgorde is belangrijk: authenticatie moet voor logging worden uitgevoerd, en caching moet voor retry-logica worden uitgevoerd.
Een productieconfiguratie kan er als volgt uitzien:
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([
// Volgorde: auth -> refresh -> cache -> retry -> logging
authInterceptor,
tokenRefreshInterceptor,
cacheInterceptor,
retryInterceptor,
loggingInterceptor,
])
),
],
});Deze volgorde zorgt ervoor dat tokens worden toegevoegd voor de refresh-afhandeling, cache-controles plaatsvinden voor retries, en logging de uiteindelijke timing vastlegt.
Voor bredere Angular-patronen, zie de RxJS fundamentals module die de operators behandelt die in interceptors worden gebruikt.
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Kernpunten voor Angular HttpClient Interceptors
- Functionele interceptors met
withInterceptors()zijn de Angular 20-standaard, met voorspelbare volgorde en betere tree-shaking dan class-based alternatieven - Gebruik
inject()binnen interceptors om toegang te krijgen tot services zonder constructor-boilerplate - Kloon requests met
req.clone()om headers te wijzigen aangezienHttpRequest-objecten onveranderlijk zijn HttpContext-tokens maken per-request gedrag expliciet op de aanroepplek in plaats van verborgen in globale configuratie- Token refresh-interceptors moeten gelijktijdige requests coordineren met
BehaviorSubjectom meerdere refresh-aanroepen te voorkomen - De volgorde van interceptors is belangrijk: authenticatie voor caching, caching voor retry, logging als laatste
Zie jij de bug in Angular?
Een echt codefragment, een verborgen bug, één poging per dag. Zonder account uit te proberen.

Geschreven door
Anthony Fillion-MailletOprichter van SharpSkill
Al meer dan 10 jaar fullstack-ontwikkelaar. Hij leidt SharpSkill en staat in voor alles wat hier verschijnt.
Bijgewerkt op 22 augustus 2026
Delen
Gerelateerde artikelen

Angular Signals en Computed in 2026: Fijnkorrelige Reactiviteit en Sollicitatievragen
Een diepgaande gids over Angular Signals, Computed Signals en het reactieve model in Angular 20+. Bevat best practices, RxJS-interoperabiliteit en veelgestelde technische sollicitatievragen.

Geavanceerde Angular Dependency Injection in 2026: Providers, Tokens en Sollicitatievragen
Het dependency injection systeem van Angular biedt fijnmazige controle over service-instantiatie via providers, tokens en hierarchische injectors. Deze diepgaande analyse behandelt provider-strategieen, de inject()-functie en relevante sollicitatievragen.

Angular Control Flow Syntax in 2026: @if, @for, @switch en Interviewvragen
Uitgebreide gids over de nieuwe Angular Control Flow Syntax met @if, @for en @switch. Performance-optimalisaties, Signal-integratie en veelgestelde interviewvragen voor Angular-ontwikkelaars.