Interceptor是一個帶有@Interceptor()裝飾器的class,Interceptor需要實作NestInterceptor介面。
cd src/modules/Shared & mkdir Interceptors
src/modules/Shared/Interceptors/logging.interceptor.ts
import { Interceptor, NestInterceptor, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
@Interceptor()
export class LoggingInterceptor implements NestInterceptor {
/*
1.dataOrRequest參數代表你可以傳入expressjs中的request object、或經由microservice、websocket傳遞的data。
2.ExecutionContext帶有兩個成員,parent和handler,其中,parent代表哪個Controller,handler是route handler的參考。
3.stream$ 是Observable,可以使用各種Observable的方法。
*/
intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
console.log('在執行方法之前...');
const now = Date.now();
/*Observable do 解釋請看http://cn.rx.js.org/class/es6/Observable.js~Observable.html#instance-method-do
*/
return stream$.do(() => { console.log(`在執行方法之後...${Date.now() - now}ms`) })
}
}
說明:請看註解,基本上很像Guards的說明XDDD。
Interceptor跟Component、Controller、Guard和Middleware一樣,都可以透過constructor依賴注入。
import { UseInterceptors } from '@nestjs/common';
import { LoggingInterceptor } from '../Shared/Interceptors/logging.interceptor';
@Controller()
//@UseGuards(RolesGuard)記得註解此行
export class UsersController {
...省略...
@Get('testInterceptor')
@UseInterceptors(LoggingInterceptor)
async testInterceptor( @Request() req, @Response() res, @Next() next) {
console.log('執行testInterceptor()');
res.status(HttpStatus.OK).json();
}
}
Interceptor可以作用在Method、Controller和全域,跟Guard一樣,nestjs很多地方的設計都有點類似。
如此,log機制建立就更為簡單,而且Interceptor加上Rxjs真的很方便,對於事件流可以有更多處理。
Response mapping
import { Interceptor, NestInterceptor, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
@Interceptor()
export class TransformInterceptor implements NestInterceptor {
intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
return stream$.map((data) => ({ "data": "be transformed" }));
}
}
預期會得到{ "data": "be transformed" }。
5.1 運用在UsersController,新增testTransformInterceptor()。
src/modules/Users/users.controller.ts
@Get('testTransformInterceptor')
@UseInterceptors(TransformInterceptor)
async testTransformInterceptor( @Request() req, @Response() res, @Next() next) {
res.status(HttpStatus.OK).json();
}
5.2 打開Postman,對http://localhost:3000/testTransformInterceptor 進行HTTP GET請求,結果如下。
說明:不符合預期,nestjs作者提醒,使用@Res() object,response mapping無法作用。
5.3 修改testTransformInterceptor()。
src/modules/Users/users.controller.ts
@Get('testTransformInterceptor')
@UseInterceptors(TransformInterceptor)
async testTransformInterceptor( ) {
return "test response";
}
5.4 打開Postman,對http://localhost:3000/testTransformInterceptor 進行HTTP GET請求,結果如下。
說明:符合預期。
Exception mapping
import { Interceptor, NestInterceptor, ExecutionContext, HttpStatus } from '@nestjs/common';
import { HttpException } from '@nestjs/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
@Interceptor()
export class ExceptionInterceptor implements NestInterceptor {
intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
return stream$.catch((err) =>
Observable.throw(
new HttpException('Exception interceptor 發威,exception被catch到', HttpStatus.BAD_GATEWAY)
))
}
}
6.1 將ExceptionInterceptor運用在UsersController,新增testExceptionInterceptor()。
src/modules/Users/users.controller.ts
@Get('testExceptionInterceptor')
@UseInterceptors(ExceptionInterceptor)
async testExceptionInterceptor(@Request() req, @Response() res, @Next() next ) {
throw new Error('test ExceptionInterceptor');
}
6.2 打開Postman,對http://localhost:3000/testExceptionInterceptor 進行HTTP GET請求,結果如下。
說明:ExceptionInterceptor()有攔截到並做出回應,這個其實也可以被Exception Filters捕捉到。
6.3 修改一下UsersController中的testExceptionInterceptor(),加上HttpExceptionFilter()。
src/modules/Users/users.controller.ts
@Get('testExceptionInterceptor')
@UseInterceptors(ExceptionInterceptor)
@UseFilters(new HttpExceptionFilter())
async testExceptionInterceptor(@Request() req, @Response() res, @Next() next ) {
throw new Error('test ExceptionInterceptor');
}
6.4 打開Postman,對http://localhost:3000/testExceptionInterceptor 進行HTTP GET請求,結果如下。
說明:有HttpExceptionFilter被捕捉到。
到這邊我們已經知道Interceptor有何功用了,對請求和回應可以做更細緻的處理。
程式碼在github