Capítulo 15: Comunicação HTTP com HttpClient e Functional Interceptors
Capítulo 15: Comunicação HTTP com HttpClient e Functional Interceptors
Especialização em Front-End com Angular • Angular 18+ • Signals, Standalone Architecture, RxJS, NgRx e SSR
🗺️ Mapa Conceitual da Pipeline de Interceptação HTTP
flowchart LR
App["Aplicação / Serviço Angular (HttpClient.get)"] --> Req["HttpRequest"]
subgraph INTERCEPTORS["Pipeline de Interceptores Funcionais (HttpInterceptorFn)"]
I1["authInterceptor (Injeta Bearer JWT)"]
I2["loggingInterceptor (Mede Latência de Rede)"]
I3["errorInterceptor (Captura 401 / 403 / 500)"]
end
Req --> I1 --> I2 --> I3
I3 --> Backend["API REST Externa / Backend"]
Backend --> Res["HttpResponse / HttpErrorResponse"]
Res --> I3 --> I2 --> I1
I1 --> App
style App fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
style INTERCEPTORS fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
style Backend fill:#fff3e0,stroke:#ff9800,stroke-width:2px
style Res fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
🏛️ 1. A Nova Arquitetura HTTP do Angular 18+
No Angular clássico, a comunicação com APIs externas dependia do HttpClientModule e da injeção de interceptores baseados em classes complexas registradas com HTTP_INTERCEPTORS e multi: true.
No Angular Standalone moderno:
- O módulo foi substituído pelo provedor funcional
provideHttpClient(). - O mecanismo de transporte agora pode utilizar a API nativa do navegador com
withFetch(), fundamental para Server-Side Rendering (SSR) e streaming. - Interceptores são agora funções puras tipadas (
HttpInterceptorFn), tornando a pipeline muito mais simples de testar, compor e auditar.
⚙️ 2. Configuração do provideHttpClient no app.config.ts
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withInterceptors, withFetch } from '@angular/common/http';
import { authInterceptor } from './core/interceptors/auth.interceptor';
import { loggingInterceptor } from './core/interceptors/logging.interceptor';
import { errorInterceptor } from './core/interceptors/error.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(
withFetch(), // Utiliza a Fetch API nativa em vez de XMLHttpRequest (essencial para SSR)
withInterceptors([authInterceptor, loggingInterceptor, errorInterceptor])
)
]
};
🛠️ 3. Implementação dos Interceptores Funcionais Padrão Ouro
3.1 Interceptor de Autenticação (authInterceptor)
Injeta o token JWT no cabeçalho Authorization: Bearer <token> de todas as requisições direcionadas para APIs seguras:
// core/interceptors/auth.interceptor.ts
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { AuthService } from '../services/auth.service';
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const auth = inject(AuthService);
const token = auth.obterTokenJwt();
// Se houver token, clona a requisição e adiciona o header de autorização
if (token) {
const reqAutenticada = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
return next(reqAutenticada);
}
// Se não houver token, segue o fluxo original
return next(req);
};
3.2 Interceptor de Tratamento Global de Erros (errorInterceptor)
Captura respostas com código HTTP de erro (401 Não Autorizado, 403 Proibido, 500 Erro Interno) e orquestra a notificação ou deslogamento:
// core/interceptors/error.interceptor.ts
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
export const errorInterceptor: HttpInterceptorFn = (req, next) => {
const router = inject(Router);
return next(req).pipe(
catchError((erro: HttpErrorResponse) => {
if (erro.status === 401) {
console.warn('Sessão expirada. Redirecionando para login...');
router.navigate(['/login']);
} else if (erro.status === 403) {
console.error('Acesso negado ao recurso solicitado.');
} else if (erro.status >= 500) {
console.error('Instabilidade no servidor externo. Tente novamente mais tarde.');
}
// Propaga o erro tratado para quem chamou
return throwError(() => erro);
})
);
};
🏷️ 4. Parametrização com HttpContext e HttpContextToken
Muitas vezes, uma requisição específica não deve receber o token de autenticação (por exemplo, a chamada pública de login) ou não deve exibir o loader global. O HttpContext permite passar metadados tipados:
import { HttpContextToken, HttpContext, HttpClient } from '@angular/common/http';
import { inject } from '@angular/core';
// 1. Criação do Token de Contexto
export const IGNORAR_AUTH = new HttpContextToken<boolean>(() => false);
// 2. Serviço consumindo com contexto customizado
export class ApiService {
private http = inject(HttpClient);
loginPublico(credenciais: any) {
return this.http.post('/api/auth/login', credenciais, {
context: new HttpContext().set(IGNORAR_AUTH, true) // Informa ao interceptor para pular
});
}
}
No interceptor:
export const authInterceptor: HttpInterceptorFn = (req, next) => {
if (req.context.get(IGNORAR_AUTH)) {
return next(req); // Pula injeção de token
}
// ...
};
⚖️ 5. Comparativo: XMLHttpRequest vs withFetch()
| Critério | provideHttpClient() Padrão (XHR) |
withFetch() Moderno |
|---|---|---|
| API do Navegador | XMLHttpRequest legada |
window.fetch() moderna |
| Streaming de Respostas | Não suportado de forma eficiente | Nativo (Server-Sent Events e streams) |
| Execução em SSR | Requer emulação de XHR no Node.js | Nativo no runtime do Node.js moderno |
| Cancelamento de Requisição | abort() via XHR |
AbortController nativo |
| Recomendação Angular 18+ | Legado | Altamente Recomendado |
⚠️ 6. Armadilhas Comuns e Anti-Patterns
- Mutar o Objeto
reqDiretamente:- As requisições HTTP do Angular são objetos imutáveis. Fazer
req.headers.append(...)não funciona! - Correção: Utilize sempre
req.clone({ ... }).
- As requisições HTTP do Angular são objetos imutáveis. Fazer
- Esquecer de Adicionar
withFetch()em Aplicações SSR:- Em projetos com Server-Side Rendering, omitir
withFetch()pode causar inconsistências na serialização de requisições durante a hidratação.
- Em projetos com Server-Side Rendering, omitir
🛡️ 7. Boas Práticas e Segurança Corporativa
- Sanitização de URLs de Destino: Valide a URL da requisição antes de injetar o token de autorização. Nunca envie seu token Bearer corporativo para domínios ou CDNs de terceiros.
- Tipagem Fiel dos DTOs: Tipar todas as respostas com generics estritos:
this.http.get<ClienteDTO[]>('/api/clientes').
📋 8. Cheat-Sheet: Resumo Executivo
// Interceptor funcional
export const meuInterceptor: HttpInterceptorFn = (req, next) => {
const clonada = req.clone({ setHeaders: { 'X-App-Version': '1.0' } });
return next(clonada);
};
// app.config.ts
provideHttpClient(withFetch(), withInterceptors([meuInterceptor]))