Angular HttpClient e Interceptors en 2026: Manejo de Peticiones y Preguntas de Entrevista
Guía completa sobre HttpClient e interceptors en Angular 2026. Arquitectura de peticiones HTTP, manejo de errores, autenticación y preguntas frecuentes en entrevistas técnicas.

Angular continúa siendo en 2026 uno de los frameworks frontend más utilizados en entornos empresariales, y el dominio de HttpClient representa una habilidad esencial para cualquier desarrollador Angular. Esta guía explora en profundidad el funcionamiento de HttpClient, la arquitectura de los interceptors funcionales, y las preguntas más frecuentes en entrevistas técnicas.
Desde Angular 15, los interceptors funcionales reemplazan progresivamente a los interceptors basados en clases. Esta guía cubre ambos enfoques, con énfasis en los patrones modernos recomendados en 2026.
Configuración de HttpClient en Angular 19
La configuración de HttpClient ha evolucionado considerablemente con la adopción de standalone components. El método moderno utiliza provideHttpClient() en la configuración de la aplicación.
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withInterceptors, withFetch } from '@angular/common/http';
import { authInterceptor } from './interceptors/auth.interceptor';
import { errorInterceptor } from './interceptors/error.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(
withInterceptors([authInterceptor, errorInterceptor]),
withFetch() // Uses fetch API instead of XMLHttpRequest
)
]
};La opción withFetch() permite utilizar la API Fetch nativa del navegador en lugar de XMLHttpRequest, ofreciendo mejor rendimiento y una integración más fluida con los Service Workers.
Creación de un Servicio HTTP Tipado
Un servicio HTTP bien estructurado constituye la base de una arquitectura Angular robusta. El uso de genéricos TypeScript garantiza la seguridad de tipos a través de toda la aplicación.
import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../environments/environment';
export interface ApiResponse<T> {
data: T;
message: string;
status: number;
}
export interface PaginatedResponse<T> {
items: T[];
total: number;
page: number;
pageSize: number;
}
@Injectable({ providedIn: 'root' })
export class ApiService {
private http = inject(HttpClient);
private baseUrl = environment.apiUrl;
get<T>(endpoint: string, params?: Record<string, string>): Observable<ApiResponse<T>> {
const httpParams = new HttpParams({ fromObject: params || {} });
return this.http.get<ApiResponse<T>>(`${this.baseUrl}${endpoint}`, { params: httpParams });
}
post<T, R>(endpoint: string, body: T): Observable<ApiResponse<R>> {
return this.http.post<ApiResponse<R>>(`${this.baseUrl}${endpoint}`, body);
}
put<T, R>(endpoint: string, body: T): Observable<ApiResponse<R>> {
return this.http.put<ApiResponse<R>>(`${this.baseUrl}${endpoint}`, body);
}
delete<T>(endpoint: string): Observable<ApiResponse<T>> {
return this.http.delete<ApiResponse<T>>(`${this.baseUrl}${endpoint}`);
}
uploadFile(endpoint: string, file: File): Observable<ApiResponse<{ url: string }>> {
const formData = new FormData();
formData.append('file', file);
return this.http.post<ApiResponse<{ url: string }>>(`${this.baseUrl}${endpoint}`, formData);
}
}Interceptors Funcionales: El Enfoque Moderno
Los interceptors funcionales introducidos en Angular 15 ofrecen una sintaxis más concisa y mejor composabilidad. Se integran perfectamente con la arquitectura standalone.
Interceptor de Autenticación
La adición automática del token de autenticación representa el caso de uso más común de los interceptors.
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { AuthService } from '../services/auth.service';
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const authService = inject(AuthService);
const token = authService.getAccessToken();
if (token && !req.url.includes('/auth/')) {
const clonedRequest = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
return next(clonedRequest);
}
return next(req);
};Interceptor de Manejo de Errores
Un interceptor centralizado para el manejo de errores simplifica considerablemente el código de los componentes.
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { catchError, throwError } from 'rxjs';
import { NotificationService } from '../services/notification.service';
export const errorInterceptor: HttpInterceptorFn = (req, next) => {
const router = inject(Router);
const notifications = inject(NotificationService);
return next(req).pipe(
catchError((error: HttpErrorResponse) => {
switch (error.status) {
case 401:
router.navigate(['/login']);
break;
case 403:
notifications.error('Access denied');
break;
case 404:
notifications.error('Resource not found');
break;
case 500:
notifications.error('Server error. Please try again later.');
break;
default:
notifications.error(error.message || 'An error occurred');
}
return throwError(() => error);
})
);
};Interceptor de Retry con Backoff Exponencial
El manejo de fallos de red transitorios requiere una estrategia de reintentos inteligente.
import { HttpInterceptorFn } from '@angular/common/http';
import { retry, timer } from 'rxjs';
export const retryInterceptor: HttpInterceptorFn = (req, next) => {
const maxRetries = 3;
const delayMs = 1000;
return next(req).pipe(
retry({
count: maxRetries,
delay: (error, retryCount) => {
if (error.status >= 400 && error.status < 500) {
throw error; // Don't retry client errors
}
const backoffDelay = delayMs * Math.pow(2, retryCount - 1);
console.log(`Retry attempt ${retryCount} after ${backoffDelay}ms`);
return timer(backoffDelay);
}
})
);
};Gestión de Caché con Interceptors
La implementación de una caché HTTP a nivel de interceptor permite optimizar el rendimiento sin modificar los servicios existentes.
import { HttpInterceptorFn, HttpResponse } from '@angular/common/http';
import { of, tap } from 'rxjs';
const cache = new Map<string, { response: HttpResponse<unknown>; timestamp: number }>();
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
export const cacheInterceptor: HttpInterceptorFn = (req, next) => {
if (req.method !== 'GET') {
return next(req);
}
const cacheKey = req.urlWithParams;
const cached = cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
return of(cached.response.clone());
}
return next(req).pipe(
tap((event) => {
if (event instanceof HttpResponse) {
cache.set(cacheKey, { response: event.clone(), timestamp: Date.now() });
}
})
);
};Interceptor de Loading Global
La visualización automática de un indicador de carga mejora la experiencia del usuario.
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { finalize } from 'rxjs';
import { LoadingService } from '../services/loading.service';
export const loadingInterceptor: HttpInterceptorFn = (req, next) => {
const loadingService = inject(LoadingService);
if (req.headers.has('X-Skip-Loading')) {
return next(req);
}
loadingService.show();
return next(req).pipe(
finalize(() => loadingService.hide())
);
};Patrones Avanzados: Refresh Token Automático
La gestión automática del refresh token representa un patrón esencial para aplicaciones seguras.
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
import { inject } from '@angular/core';
import { BehaviorSubject, throwError } from 'rxjs';
import { catchError, filter, switchMap, take } from 'rxjs/operators';
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) {
return refreshTokenSubject.pipe(
filter((token) => token !== null),
take(1),
switchMap((token) => {
const cloned = req.clone({
setHeaders: { Authorization: `Bearer ${token}` }
});
return next(cloned);
})
);
}
isRefreshing = true;
refreshTokenSubject.next(null);
return authService.refreshToken().pipe(
switchMap((response) => {
isRefreshing = false;
refreshTokenSubject.next(response.accessToken);
const cloned = req.clone({
setHeaders: { Authorization: `Bearer ${response.accessToken}` }
});
return next(cloned);
}),
catchError((refreshError) => {
isRefreshing = false;
authService.logout();
return throwError(() => refreshError);
})
);
})
);
};¿Listo para aprobar tus entrevistas de Angular?
Practica con nuestros simuladores interactivos, flashcards y tests técnicos.
Preguntas Frecuentes en Entrevistas
Las siguientes preguntas aparecen regularmente durante las entrevistas técnicas de Angular.
¿Cuál es la diferencia entre HttpClient y la API Fetch nativa?
HttpClient ofrece varias ventajas sobre la API Fetch: integración nativa con RxJS, sistema de interceptors, tipado fuerte con TypeScript, y manejo automático de serialización JSON. La API Fetch es más ligera pero requiere más código boilerplate.
¿Cómo funciona el orden de ejecución de los interceptors?
Los interceptors se ejecutan en el orden de su declaración para las peticiones salientes, y en orden inverso para las respuestas entrantes. Esta arquitectura en "cebolla" permite encadenar las transformaciones de manera predecible.
¿Cómo cancelar una petición HTTP en curso?
La cancelación se realiza mediante la desuscripción al Observable retornado por HttpClient. El uso del operador takeUntil con un Subject permite gestionar correctamente la cancelación durante la destrucción de un componente.
// Example: Cancelling requests on component destroy
import { Component, OnDestroy } from '@angular/core';
import { Subject, takeUntil } from 'rxjs';
@Component({ /* ... */ })
export class SearchComponent implements OnDestroy {
private destroy$ = new Subject<void>();
search(term: string) {
this.apiService.search(term)
.pipe(takeUntil(this.destroy$))
.subscribe(results => this.results = results);
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}¿Cuándo usar HttpParams vs un objeto simple?
HttpParams garantiza la codificación correcta de los parámetros URL y soporta valores múltiples para una misma clave. Un objeto simple es adecuado para casos simples, pero HttpParams se recomienda para peticiones complejas.
¿Cómo probar un servicio que utiliza HttpClient?
Angular proporciona HttpTestingController para simular las peticiones HTTP en pruebas unitarias. Este enfoque permite verificar las URLs llamadas, los headers enviados, y simular diferentes respuestas.
// Example: Testing HTTP service
import { TestBed } from '@angular/core/testing';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { provideHttpClient } from '@angular/common/http';
describe('ApiService', () => {
let service: ApiService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
provideHttpClient(),
provideHttpClientTesting()
]
});
service = TestBed.inject(ApiService);
httpMock = TestBed.inject(HttpTestingController);
});
it('should fetch users', () => {
const mockUsers = [{ id: 1, name: 'John' }];
service.get<User[]>('/users').subscribe(response => {
expect(response.data).toEqual(mockUsers);
});
const req = httpMock.expectOne('/api/users');
expect(req.request.method).toBe('GET');
req.flush({ data: mockUsers, message: 'OK', status: 200 });
});
afterEach(() => {
httpMock.verify();
});
});Buenas Prácticas en 2026
Varias recomendaciones emergen para un uso óptimo de HttpClient en producción.
La centralización de las llamadas HTTP en servicios dedicados facilita el mantenimiento y las pruebas. El uso sistemático de interceptors para preocupaciones transversales (autenticación, logging, caché) evita la duplicación de código.
El tipado estricto de todas las respuestas API con interfaces TypeScript permite detectar errores en tiempo de compilación. La adopción de interceptors funcionales simplifica la configuración y mejora el rendimiento gracias al tree-shaking.
El manejo explícito de errores en cada nivel (interceptor global para errores comunes, manejo específico en componentes para casos particulares) garantiza una experiencia de usuario coherente.
Conclusión
HttpClient y los interceptors constituyen la base de la comunicación HTTP en aplicaciones Angular. El dominio de estos conceptos, desde los patrones básicos hasta técnicas avanzadas como el refresh token automático, representa una competencia clave evaluada en las entrevistas técnicas. La adopción de interceptors funcionales y las buenas prácticas presentadas en esta guía permite construir aplicaciones robustas y mantenibles.
¿Sabrías detectar el bug en Angular?
Un fragmento real, un bug oculto, un intento al día. Sin cuenta para probar.

Escrito por
Anthony Fillion-MailletFundador de SharpSkill
Desarrollador fullstack desde hace más de 10 años. Dirige SharpSkill y responde por todo lo que se publica aquí.
Actualizado el 22 de agosto de 2026
Etiquetas
Compartir
Artículos relacionados

Inyección de Dependencias Avanzada en Angular 2026: Providers, Tokens y Preguntas de Entrevista
Dominar la inyección de dependencias en Angular con InjectionToken, inyectores jerárquicos, modificadores de resolución y multi-providers. Incluye preguntas de entrevista y patrones de producción.

RxJS en Angular 2026: operators, Subjects e interop con Signals
RxJS en Angular 2026: domina los operators, los Subjects y los patrones de interop con Signals que se usan en producción, además de las preguntas de entrevista más frecuentes.

Angular 20 en 2026: Resource API, httpResource y preguntas de entrevista
Angular 20 introduce httpResource y estabiliza la Resource API para la obtención de datos basada en signals. Un tutorial práctico sobre resource(), rxResource(), httpResource(), la validación con Zod y las preguntas de entrevista más comunes.