Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteAngular interceptors let you apply shared behavior around HttpClient calls: add or scope authentication headers, log traffic, handle errors, retry requests, or observe responses. For new applications, Angular recommends functional interceptors registered with provideHttpClient(withInterceptors([...])). Clone requests rather than changing them in place, and treat the result of next(req) as an event stream—not as a single response.
How Angular interceptors work
An interceptor sits between an HttpClient call and the next handler in the HTTP pipeline. It receives an outgoing HttpRequest and a next function. It can forward the request unchanged, forward a modified clone, transform the response event stream, or—in cases such as a cache hit—return a response without forwarding the request.
As an Amazon Associate I earn from qualifying purchases.
Interceptors run in the order they are registered on the way out. Responses travel back through the chain in reverse order. This makes registration order important when one interceptor depends on another—for example, when logging should see a request after an authentication header has been added.
Register a functional interceptor
Functional interceptors are Angular’s recommended option for predictable behavior, especially in complex configurations. Register them in the application’s providers with provideHttpClient and withInterceptors:
#1 Best Overall
import { provideHttpClient, withInterceptors } from '@angular/common/http';
export const appConfig = {
providers: [
provideHttpClient(
withInterceptors([authInterceptor, loggingInterceptor]),
),
],
};
The listed order is the outgoing request order. A functional interceptor runs in the injection context of the injector where it was registered, so it can use Angular’s inject() function to obtain services.
Add an authentication header safely
Use req.clone() to create the request with updated headers. The service and header below are illustrative; use the credential source and header expected by your API.
Rank #2
import { inject } from '@angular/core';
import { HttpInterceptorFn } from '@angular/common/http';
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const authToken = inject(AuthService).getAuthToken();
const authenticatedReq = req.clone({
headers: req.headers.set('X-Authentication-Token', authToken),
});
return next(authenticatedReq);
};
Do not attach a secret to every request automatically. Restrict credentials to the API origins and paths that are meant to receive them. A broadly registered interceptor may also see requests to unrelated services, such as an image host or a third-party API.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Requests and responses are mostly immutable: update them by cloning, and use immutable header or parameter APIs such as set() and append(). Their bodies are not deeply immutable, however. Avoid changing an object body in place; if the request is retried, the same interceptor can run again and observe the already-mutated body.
Rank #3
Choose between functional and class-based interceptors
| Approach | Registration | When it fits |
|---|---|---|
| Functional | provideHttpClient(withInterceptors([myInterceptor])) |
Recommended for new code and for configurations where predictable ordering matters. |
| Class-based, DI-provided | Register a class with the HTTP_INTERCEPTORS multi-provider, then enable it with withInterceptorsFromDi(). |
Useful when retaining an existing class-interceptor setup. Angular continues to support this approach, though ordering can be harder to predict in extensive or hierarchical dependency-injection configurations. |
A class interceptor implements HttpInterceptor and defines an intercept(req, next) method. If you use this form, include both the multi-provider registration and withInterceptorsFromDi() in the HTTP client setup; registering the class alone is not the complete configuration.
Read responses without confusing them with other events
An interceptor’s next(req) returns an Observable of HttpEvent values. Depending on the request and configuration, that stream can include progress or other lifecycle events as well as the final response. Check the event type before accessing response-specific fields:
Rank #4
import { HttpEventType, HttpInterceptorFn } from '@angular/common/http';
import { tap } from 'rxjs';
export const responseLoggerInterceptor: HttpInterceptorFn = (req, next) =>
next(req).pipe(
tap(event => {
if (event.type === HttpEventType.Response) {
console.log('HTTP status:', event.status);
}
}),
);
Use an interceptor’s event stream when you need cross-cutting observation or transformation. In ordinary application code, HttpClient returns the response body by default. Set observe: 'response' on a request when its caller needs the full response object, including status and headers.
Handle errors in the Observable error channel
HTTP failures do not arrive as successful response events. Angular reports them through the Observable error channel as HttpErrorResponse. A network or connection failure and a configured timeout use status 0; a backend error carries the status returned by the server. An interceptor can apply shared handling with RxJS operators, while allowing callers to receive the error when appropriate.
import { HttpErrorResponse, HttpInterceptorFn } from '@angular/common/http';
import { catchError, throwError } from 'rxjs';
export const errorLoggingInterceptor: HttpInterceptorFn = (req, next) =>
next(req).pipe(
catchError((error: HttpErrorResponse) => {
console.error('Request failed:', error.status, error.message);
return throwError(() => error);
}),
);
Logging and rethrowing preserves the failure for request-specific code to handle. If an interceptor instead converts an error into a successful fallback value, callers will observe that fallback as success; use that behavior only when it is intentional.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Use context for interceptor-only metadata
When an interceptor needs per-request instructions that should not become an HTTP header or query parameter, use a typed HttpContextToken. The context is mutable even though most request fields are immutable, so context state can persist when a request is retried. Account for that persistence when storing flags or retry-related metadata.
Return a synthetic response only when bypassing the chain is intended
An interceptor can return an HttpResponse directly—for example, when a cache can satisfy a request—without calling next(req). This stops the request from reaching the backend and also skips every downstream interceptor. Consider the chain order before using this pattern: any downstream logging, transformation, or error behavior will not run for the synthetic response.
Test an interceptor with Angular’s HTTP testing utilities
Test the behavior one interceptor at a time: configure the HTTP client with the interceptor under test, make a request, capture it with HttpTestingController, assert the changed request fields, and then flush a representative result. Use the testing controller’s network-error mechanism for a connection failure.
import { TestBed } from '@angular/core/testing';
import {
provideHttpClient,
withInterceptors,
} from '@angular/common/http';
import {
HttpTestingController,
provideHttpClientTesting,
} from '@angular/common/http/testing';
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
provideHttpClient(withInterceptors([authInterceptor])),
provideHttpClientTesting(),
],
});
});
afterEach(() => {
TestBed.inject(HttpTestingController).verify();
});
In a test, inject HttpClient and HttpTestingController, subscribe to the request, then use expectOne() to capture it. Assert the relevant header or other modification on the captured request. Call flush() with a success or backend error to test those paths; use error() with a ProgressEvent to simulate a network error. Verify outstanding requests are cleared so a test cannot pass while leaving an unexpected call behind.
Quick Recap
Official Angular references
- Angular: HTTP interceptors
- Angular: Setting up HttpClient
- Angular: Making HTTP requests
- Angular: Testing HTTP requests
- Angular API: HttpInterceptor
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




