Intercettori
Fa parte della sezione TypeScript e NestJS del percorso Node.js di Coddy. Lezione 23 di 24.
Vuoi che ogni risposta indichi quanto tempo ci è voluto, senza modificare ogni gestore. Un interceptor avvolge il gestore: il codice prima di next.handle() viene eseguito prima, mentre il codice sul valore restituito da next.handle() viene eseguito dopo.
intercept(context: ExecutionContext, next: CallHandler) {
console.log('before');
return next.handle().pipe(
tap(() => console.log('after')),
);
}next.handle() fornisce il risultato del gestore come osservabile RxJS, un valore che arriva in seguito. .pipe(tap(...)) esegue una funzione quando arriva il valore, prima che Nest lo invii; questo pipe non ha nulla a che fare con le pipe di validazione di Nest. Le guardie vengono eseguite prima di qualsiasi interceptor, quindi una richiesta rifiutata da una guardia non lo raggiunge mai. Restituisci l’osservabile con la pipe: Nest invia ciò che contiene. context.switchToHttp().getResponse() fornisce res, il cui setHeader aggiunge un’intestazione.
app.useGlobalInterceptors(...) applica un interceptor a ogni route; @UseInterceptors(...) a un solo controller.
Sfida
FacileRun avvia di nuovo il tuo tracker, usando src/main.ts. I file separati per gli esercizi possono restare nell'albero; questo server non li avvia.
I client e il tuo sistema di monitoraggio vogliono sapere quanto tempo ha impiegato ogni richiesta. Aggiungi un'intestazione di risposta, X-Response-Time, a ogni risposta riuscita, senza modificare alcuna route.
- Apri
src/common/response-time.interceptor.ts. Nel metodointerceptdiResponseTimeInterceptor, annota per prima cosa l'ora corrente conDate.now(). Il codice all'inizio diinterceptviene eseguito prima del metodo della route. - Ottieni
resdi Express concontext.switchToHttp().getResponse(). next.handle()esegue il metodo della route e restituisce il risultato come observable di RxJS: un valore che arriva in seguito. Continua a restituirlo, ma passalo attraversotap, già importato darxjs, usando il metodo.pipe()dell'observable. La funzione che passi atapviene eseguita quando arriva il risultato, prima che Nest lo invii. In quella funzione, chiamares.setHeaderper impostareX-Response-Timesul numero di millisecondi trascorsi da quando hai annotato l'ora, seguito dams, come in3ms. (.pipe()di RxJS non ha nulla a che fare con i pipe di convalida del capitolo 3. Aggiunge un passaggio alla catena dell'observable.)- In
src/main.ts, registra l'interceptor per l'intera app conapp.useGlobalInterceptors(...), passando una nuova istanza diResponseTimeInterceptor, accanto al pipe e al filtro. - I corpi delle risposte non devono cambiare.
GET /taskscontinua a restituire{ "items": [...], "page": 1, "total": 3, "pages": 2 }.
Prova: invia GET /tasks e apri la scheda Headers della risposta. Vedrai X-Response-Time con un valore come 0ms o 2ms. Anche GET /stats lo include, così come una richiesta POST con { "title": "Buy milk" } inviata con l'intestazione x-api-key: tasks-key-123. Poi invia quella POST senza la chiave: 403, e nessun X-Response-Time. Nest esegue le guardie prima degli interceptor, quindi la guardia ha rifiutato la richiesta prima che l'interceptor si avviasse. Anche un errore generato all'interno di una route esclude l'intestazione, perché tap viene eseguito solo quando arriva un risultato.
Provalo tu
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> {
// Registra l'ora, lascia eseguire l'handler, poi imposta X-Response-Time.
return next.handle();
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di TypeScript e NestJS
Esercitati da solo: Playground Express