Interceptors
Teil des Abschnitts TypeScript und NestJS der Node.js-Journey von Coddy. Lektion 23 von 24.
Du möchtest, dass jede Antwort angibt, wie lange sie gedauert hat, ohne jeden Handler einzeln anzupassen. Ein Interceptor umschließt den Handler: Code vor next.handle() wird davor ausgeführt, und Code für das, was next.handle() zurückgibt, wird danach ausgeführt.
intercept(context: ExecutionContext, next: CallHandler) {
console.log('before');
return next.handle().pipe(
tap(() => console.log('after')),
);
}next.handle() liefert das Ergebnis des Handlers als RxJS-Observable, also einen Wert, der später eintrifft. .pipe(tap(...)) führt eine Funktion aus, wenn der Wert eintrifft, bevor Nest ihn sendet; dieses pipe hat nichts mit Nests Validierungs-Pipes zu tun. Guards werden vor jedem Interceptor ausgeführt, daher erreicht eine Anfrage, die ein Guard ablehnt, ihn nie. Gib das Observable mit der Pipe zurück: Nest sendet, was es enthält. context.switchToHttp().getResponse() liefert res, dessen setHeader einen Header hinzufügt.
app.useGlobalInterceptors(...) wendet einen Interceptor auf jede Route an; @UseInterceptors(...) auf einen einzelnen Controller.
Aufgabe
Einfach„Run“ startet deinen Tracker mit src/main.ts erneut. Die separaten Übungsdateien können im Verzeichnisbaum bleiben; dieser Server startet sie nicht.
Clients und deine eigene Überwachung möchten wissen, wie lange jede Anfrage gedauert hat. Füge jeder erfolgreichen Antwort den Antwort-Header X-Response-Time hinzu, ohne eine Route anzufassen.
- Öffne
src/common/response-time.interceptor.ts. Notiere in der MethodeinterceptvonResponseTimeInterceptorzuerst die aktuelle Zeit mitDate.now(). Code am Anfang voninterceptwird vor der Routenmethode ausgeführt. - Hole dir Express’
resmitcontext.switchToHttp().getResponse(). next.handle()führt die Routenmethode aus und liefert ihr Ergebnis als RxJS-Observable zurück: einen Wert, der später eintrifft. Gib es weiterhin zurück, aber leite es mithilfe der Observable-Methode.pipe()durchtap, das bereits ausrxjsimportiert wurde. Die Funktion, die dutapübergibst, wird ausgeführt, wenn das Ergebnis eintrifft, bevor Nest es sendet. Rufe in dieser Funktionres.setHeaderauf, umX-Response-Timeauf die Millisekunden seit der notierten Zeit zu setzen, gefolgt vonms, zum Beispiel3ms. (RxJS’.pipe()hat nichts mit den Validierungs-Pipes aus Kapitel 3 zu tun. Damit wird dem Observable ein Schritt hinzugefügt.)- Registriere in
src/main.tsden Interceptor für die gesamte App mitapp.useGlobalInterceptors(...), indem du eine neue Instanz vonResponseTimeInterceptorübergibst, neben der Pipe und dem Filter. - Die Antwortinhalte dürfen sich nicht ändern.
GET /tasksgibt weiterhin{ "items": [...], "page": 1, "total": 3, "pages": 2 }zurück.
Probiere es aus: Sende GET /tasks und öffne den Tab „Headers“ der Antwort. Dort siehst du X-Response-Time mit einem Wert wie 0ms oder 2ms. Auch GET /stats enthält diesen Header, ebenso ein POST mit { "title": "Buy milk" }, der mit dem Header x-api-key: tasks-key-123 gesendet wird. Sende diesen POST dann ohne den Schlüssel: 403 und kein X-Response-Time. Nest führt Guards vor Interceptors aus, daher hat der Guard die Anfrage abgelehnt, bevor dein Interceptor gestartet wurde. Auch ein innerhalb einer Route ausgelöster Fehler verhindert den Header, denn tap wird nur ausgeführt, wenn ein Ergebnis eintrifft.
Probier es selbst
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> {
// Erfasse die Zeit, lasse den Handler laufen und setze dann X-Response-Time.
return next.handle();
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in TypeScript und NestJS
1Nest-Grundlagen
Klassen und MethodenHallo, NestEinen Controller registrieren4Guards, Filter und Interceptors
GuardsÜbe selbstständig: Express-Playground