Menu
CoddyTech

Interceptory

Część sekcji TypeScript i NestJS ścieżki Node.js w Coddy. Lekcja 23 z 24.

Chcesz, aby każda odpowiedź informowała, ile czasu to zajęło, bez modyfikowania każdego handlera. Interceptor otacza handler: kod przed next.handle() wykonuje się przed nim, a kod uruchamiany na tym, co zwraca next.handle(), wykonuje się po nim.

intercept(context: ExecutionContext, next: CallHandler) {
    console.log('before');
    return next.handle().pipe(
        tap(() => console.log('after')),
    );
}

next.handle() zwraca wynik handlera jako observable RxJS, czyli wartość, która pojawia się później. .pipe(tap(...)) uruchamia funkcję, gdy pojawi się wartość, zanim Nest ją wyśle; to pipe nie ma nic wspólnego z potokami walidacji Nest. Guardy uruchamiają się przed każdym interceptorem, więc żądanie odrzucone przez guarda nigdy do niego nie dotrze. Zwróć observable z potokiem: Nest wysyła to, co on zawiera. context.switchToHttp().getResponse() zwraca res, którego setHeader dodaje nagłówek.

app.useGlobalInterceptors(...) stosuje interceptor do każdej trasy; @UseInterceptors(...) — do jednego kontrolera.

challenge icon

Wyzwanie

Łatwy

Uruchom ponownie swój tracker, używając src/main.ts. Oddzielne pliki ćwiczeniowe mogą pozostać w drzewie; ten serwer ich nie uruchamia.

Klienci i Twoje własne narzędzia monitorujące chcą wiedzieć, ile czasu zajęło każde żądanie. Dodaj nagłówek odpowiedzi X-Response-Time do każdej pomyślnej odpowiedzi, nie zmieniając żadnej trasy.

  1. Otwórz src/common/response-time.interceptor.ts. W metodzie intercept klasy ResponseTimeInterceptor najpierw zapisz bieżący czas za pomocą Date.now(). Kod na początku metody intercept uruchamia się przed metodą trasy.
  2. Pobierz res Expressa za pomocą context.switchToHttp().getResponse().
  3. next.handle() uruchamia metodę trasy i zwraca jej wynik jako obserwowalny obiekt RxJS: wartość, która pojawia się później. Nadal go zwracaj, ale przekaż go przez tap, który jest już zaimportowany z rxjs, za pomocą metody .pipe() obserwowalnego obiektu. Funkcja przekazana do tap uruchamia się, gdy pojawi się wynik, przed wysłaniem go przez Nest. W tej funkcji wywołaj res.setHeader, aby ustawić X-Response-Time na liczbę milisekund od zapisania czasu, po której następuje ms, na przykład 3ms. (.pipe() w RxJS nie ma nic wspólnego z potokami walidacyjnymi z rozdziału 3. Dodaje krok do łańcucha obserwowalnego obiektu.)
  4. W pliku src/main.ts zarejestruj interceptor dla całej aplikacji za pomocą app.useGlobalInterceptors(...), przekazując nowy obiekt ResponseTimeInterceptor, obok potoku i filtra.
  5. Treść odpowiedzi nie może się zmienić. GET /tasks nadal zwraca { "items": [...], "page": 1, "total": 3, "pages": 2 }.

Wypróbuj: wyślij GET /tasks i otwórz kartę Nagłówki odpowiedzi. Zobaczysz X-Response-Time z wartością taką jak 0ms lub 2ms. Jest on również obecny w GET /stats oraz w żądaniu POST z treścią { "title": "Buy milk" }, wysłanym z nagłówkiem x-api-key: tasks-key-123. Następnie wyślij to żądanie POST bez klucza: 403 i brak X-Response-Time. Nest uruchamia strażników przed interceptorami, więc strażnik odrzucił żądanie, zanim uruchomił się Twój interceptor. Błąd zgłoszony wewnątrz trasy również pomija ten nagłówek, ponieważ tap uruchamia się tylko wtedy, gdy pojawi się wynik.

Spróbuj swoich sił

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> {
        // Zanotuj czas, pozwól wykonać się handlerowi, a następnie ustaw X-Response-Time.
        return next.handle();
    }
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji TypeScript i NestJS

Poćwicz samodzielnie: Edytor online Express