Interceptadores
Parte da seção TypeScript e NestJS do Journey de Node.js da Coddy. Lição 23 de 24.
Você quer que cada resposta informe quanto tempo levou, sem precisar mexer em cada handler. Um interceptor envolve o handler: o código antes de next.handle() é executado antes dele, e o código sobre o que next.handle() retorna é executado depois.
intercept(context: ExecutionContext, next: CallHandler) {
console.log('before');
return next.handle().pipe(
tap(() => console.log('after')),
);
}next.handle() fornece o resultado do handler como um observável do RxJS, um valor que chega mais tarde. .pipe(tap(...)) executa uma função quando o valor chega, antes de o Nest enviá-lo; esse pipe não tem nada a ver com os pipes de validação do Nest. Os guards são executados antes de qualquer interceptor, então uma solicitação recusada por um guard nunca chega até ele. Retorne o observável encadeado com pipe: o Nest envia o que ele carrega. context.switchToHttp().getResponse() fornece res, cujo setHeader adiciona um cabeçalho.
app.useGlobalInterceptors(...) aplica um interceptor a todas as rotas; @UseInterceptors(...), a um único controller.
Desafio
FácilRun inicia seu rastreador novamente, usando src/main.ts. Os arquivos de prática separados podem permanecer na árvore; este servidor não os inicia.
Os clientes e seu próprio monitoramento querem saber quanto tempo cada solicitação levou. Adicione um cabeçalho de resposta, X-Response-Time, a cada resposta bem-sucedida, sem mexer em nenhuma rota.
- Abra
src/common/response-time.interceptor.ts. No métodointerceptdeResponseTimeInterceptor, primeiro registre o horário atual comDate.now(). O código no início deintercepté executado antes do método da rota. - Obtenha o
resdo Express comcontext.switchToHttp().getResponse(). next.handle()executa o método da rota e retorna o resultado como um observable do RxJS: um valor que chega depois. Continue retornando-o, mas passe-o portap, que já está importado derxjs, usando o método.pipe()do observable. A função que você passa paratapé executada quando o resultado chega, antes de o Nest enviá-lo. Nessa função, chameres.setHeaderpara definirX-Response-Timecomo o número de milissegundos desde que você registrou o horário, seguido dems, como em3ms. (O.pipe()do RxJS não tem relação com os pipes de validação do capítulo 3. Ele encadeia uma etapa ao observable.)- Em
src/main.ts, registre o interceptor para todo o app comapp.useGlobalInterceptors(...), passando uma nova instância deResponseTimeInterceptor, junto ao pipe e ao filtro. - Os corpos das respostas não devem mudar.
GET /tasksainda retorna{ "items": [...], "page": 1, "total": 3, "pages": 2 }.
Experimente: envie GET /tasks e abra a aba Headers da resposta. Você verá X-Response-Time com um valor como 0ms ou 2ms. GET /stats também o inclui, assim como uma solicitação POST de { "title": "Buy milk" } enviada com o cabeçalho x-api-key: tasks-key-123. Em seguida, envie esse POST sem a chave: 403, e sem X-Response-Time. O Nest executa os guards antes dos interceptors, então o guard recusou a solicitação antes de o interceptor começar. Um erro lançado dentro de uma rota também faz com que o cabeçalho seja omitido, porque tap só é executado quando um resultado chega.
Experimente você mesmo
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable, tap } from 'rxjs';
@Injectable()
export class ResponseTimeInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
// Registre o horário, deixe o handler executar e, em seguida, defina X-Response-Time.
return next.handle();
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de TypeScript e NestJS
1Fundamentos do Nest
Classes e métodosOlá, NestRegistrando um controller4Guardas, filtros e interceptadores
GuardasPratique por conta própria: Playground de Express