Sự khác biệt duy nhất giữa lớp exception filter của HTTP và lớp tương ứng của microservices là thay vì throw HttpException, bạn nên dùng RpcException.
throw new RpcException('Invalid credentials.');
Gợi ý Class RpcException được import từ package @nestjs/microservices.
Cảnh báo Một event handler không có response stream. Một filter re-throw lỗi cho handler @EventPattern sẽ khiến lỗi đó không đi đến đâu cả, vì vậy hãy xử lý lỗi ngay trong filter.
Với ví dụ trên, Nest sẽ xử lý exception được throw và trả về object error với cấu trúc sau:
{
"status": "error",
"message": "Invalid credentials."
}
Filter
Exception filter của microservices hoạt động tương tự exception filter của HTTP, chỉ khác một điểm nhỏ. Method catch() phải trả về một Observable.
import { Catch, RpcExceptionFilter, ArgumentsHost } from '@nestjs/common';
import { Observable, throwError } from 'rxjs';
import { RpcException } from '@nestjs/microservices';
@Catch(RpcException)
export class ExceptionFilter implements RpcExceptionFilter<RpcException> {
catch(exception: RpcException, host: ArgumentsHost): Observable<any> {
return throwError(() => exception.getError());
}
}
import { Catch } from '@nestjs/common';
import { throwError } from 'rxjs';
@Catch(RpcException)
export class ExceptionFilter {
catch(exception, host) {
return throwError(() => exception.getError());
}
}
Cảnh báo Exception filter global cho microservices không được bật theo mặc định khi dùng hybrid application.
Ví dụ sau dùng một filter method-scoped được khởi tạo thủ công. Giống như với ứng dụng dựa trên HTTP, bạn cũng có thể dùng filter controller-scoped (nghĩa là, thêm decorator @UseFilters() lên đầu class controller).
@UseFilters(new ExceptionFilter())
@MessagePattern({ cmd: 'sum' })
accumulate(data: number[]): number {
return (data || []).reduce((a, b) => a + b);
}
@UseFilters(new ExceptionFilter())
@MessagePattern({ cmd: 'sum' })
accumulate(data) {
return (data || []).reduce((a, b) => a + b);
}
Kế thừa (Inheritance)
Thông thường, bạn sẽ tạo các exception filter được tùy chỉnh hoàn toàn để đáp ứng nhu cầu của ứng dụng. Tuy nhiên, có những use case mà bạn chỉ muốn đơn giản là kế thừa exception filter cốt lõi (core), và override hành vi dựa trên một số yếu tố nhất định.
Để giao (delegate) việc xử lý exception cho filter cơ sở, bạn cần kế thừa BaseExceptionFilter và gọi method catch() đã được kế thừa.
import { Catch, ArgumentsHost } from '@nestjs/common';
import { BaseRpcExceptionFilter } from '@nestjs/microservices';
@Catch()
export class AllExceptionsFilter extends BaseRpcExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
return super.catch(exception, host);
}
}
import { Catch } from '@nestjs/common';
import { BaseRpcExceptionFilter } from '@nestjs/microservices';
@Catch()
export class AllExceptionsFilter extends BaseRpcExceptionFilter {
catch(exception, host) {
return super.catch(exception, host);
}
}
Đoạn code trên chỉ là một “vỏ” (shell) minh họa cách tiếp cận. Trong thực tế, exception filter mở rộng của bạn sẽ chứa business logic riêng (ví dụ xử lý các điều kiện khác nhau).
Ghi chú người dịch Ở PHP/Laravel, đây tương đương với việc bạn tạo một ExceptionHandler tùy chỉnh kế thừa từ handler mặc định và override method render(), nhưng vẫn gọi parent::render() cho các case bạn không muốn tự xử lý. Cơ chế “kế thừa rồi gọi lại super” giúp bạn chỉ can thiệp vào đúng phần logic cần thay đổi, còn lại để framework xử lý như cũ.