Bộ đánh chặn
Thuộc phần TypeScript và NestJS trong hành trình Node.js của Coddy. Bài học 23 trên 24.
Bạn muốn mỗi câu trả lời đều cho biết mất bao lâu, mà không cần sửa từng handler. Một interceptor bọc quanh handler: code trước next.handle() chạy trước, còn code chạy trên kết quả trả về từ next.handle() sẽ chạy sau.
intercept(context: ExecutionContext, next: CallHandler) {
console.log('before');
return next.handle().pipe(
tap(() => console.log('after')),
);
}next.handle() trả về kết quả của handler dưới dạng observable của RxJS, một giá trị sẽ đến sau. .pipe(tap(...)) chạy một hàm khi giá trị đến, trước khi Nest gửi giá trị đó; pipe này không liên quan đến các pipe xác thực của Nest. Guard chạy trước mọi interceptor, nên yêu cầu bị guard từ chối sẽ không bao giờ đến interceptor. Hãy trả về observable đã qua pipe: Nest gửi dữ liệu mà observable chứa. context.switchToHttp().getResponse() trả về res, và setHeader của nó thêm một header.
app.useGlobalInterceptors(...) áp dụng interceptor cho mọi route; @UseInterceptors(...) áp dụng cho một controller.
Thử thách
DễNút Chạy khởi động lại ứng dụng theo dõi của bạn bằng src/main.ts. Các tệp luyện tập riêng có thể vẫn nằm trong thư mục, máy chủ này không khởi động chúng.
Ứng dụng khách và công cụ giám sát của bạn cần biết mỗi yêu cầu mất bao lâu. Thêm tiêu đề phản hồi X-Response-Time vào mọi phản hồi thành công mà không chỉnh sửa bất kỳ route nào.
- Mở
src/common/response-time.interceptor.ts. Trong phương thứcinterceptcủaResponseTimeInterceptor, trước tiên hãy ghi lại thời gian hiện tại bằngDate.now(). Code ở đầuinterceptchạy trước phương thức của route. - Lấy
rescủa Express bằngcontext.switchToHttp().getResponse(). next.handle()chạy phương thức của route và trả về kết quả dưới dạng observable của RxJS (observable): một giá trị sẽ đến sau. Tiếp tục trả về giá trị đó, nhưng truyền nó quatap, vốn đã được import từrxjs, bằng phương thức.pipe()của observable. Hàm bạn truyền chotapchạy khi kết quả đến, trước khi Nest gửi kết quả đi. Trong hàm đó, gọires.setHeaderđể đặtX-Response-Timethành số mili giây kể từ lúc bạn ghi lại thời gian, theo sau làms, chẳng hạn như3ms. (Phương thức.pipe()của RxJS không liên quan đến các validation pipe ở chương 3. Nó nối thêm một bước vào observable.)- Trong
src/main.ts, đăng ký interceptor cho toàn bộ ứng dụng bằngapp.useGlobalInterceptors(...), truyền vào một đối tượngResponseTimeInterceptormới, bên cạnh pipe và filter. - Nội dung phản hồi không được thay đổi.
GET /tasksvẫn trả về{ "items": [...], "page": 1, "total": 3, "pages": 2 }.
Thử nhé: gửi GET /tasks rồi mở thẻ Headers của phản hồi. Bạn sẽ thấy X-Response-Time với giá trị như 0ms hoặc 2ms. GET /stats cũng có tiêu đề này, POST với { "title": "Buy milk" } được gửi kèm tiêu đề x-api-key: tasks-key-123 cũng vậy. Sau đó, gửi POST đó mà không có khóa: 403 và không có X-Response-Time. Nest chạy guard trước interceptor, nên guard đã từ chối yêu cầu trước khi interceptor của bạn bắt đầu chạy. Lỗi phát sinh bên trong route cũng khiến tiêu đề không được thêm vào, vì tap chỉ chạy khi có kết quả.
Tự làm thử
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> {
// Ghi lại thời gian, cho handler chạy, rồi đặt X-Response-Time.
return next.handle();
}
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong TypeScript và NestJS
1Nest cơ bản
Lớp và phương thứcXin chào, NestĐăng ký controller4Bộ bảo vệ, bộ lọc và bộ đánh chặn
Bộ bảo vệTự luyện tập: Playground Express