拦截器
拦截器
拦截器(Interceptors)是一个使用

拦截器有一系列的功能,这些功能的设计灵感都来自于面向切面的编程(AOP)技术。这使得下面这些功能成为可能:
- 在函数执行前
/ 后绑定额外的逻辑 - 转换一个函数的返回值
- 转换函数抛出的异常
- 扩展基础函数的行为
- 根据特定的条件完全的重写一个函数(比如:缓存)
基础
每个拦截器都要实现
执行上下文
export interface ExecutionContext extends ArgumentsHost {
getClass<T = any>(): Type<T>;
getHandler(): Function;
}
调用处理器
第二个参数是一个
不像守卫与过滤器,拦截器对于一次请求响应有完全的控制权与责任。这样的方式意味着
假如有一个
切面拦截
我们将要研究的第一个例子就是用户登录的交互。下面展示了一个简单的日志拦截器:
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log("Before...");
const now = Date.now();
return next
.handle()
.pipe(tap(() => console.log(`After... ${Date.now() - now}ms`)));
}
}
由于
绑定拦截器
我们可以使用
@UseInterceptors(LoggingInterceptor)
export class CatsController {}
上面的实现,在请求进入
Before...
After... 1ms
案例
响应映射
我们已经知道了
export interface Response<T> {
data: T;
}
@Injectable()
export class TransformInterceptor<T>
implements NestInterceptor<T, Response<T>> {
intercept(
context: ExecutionContext,
next: CallHandler
): Observable<Response<T>> {
return next.handle().pipe(map(data => ({ data })));
}
}
当有请求进入时,响应看起来将会是下面这样:
{
"data": []
}
拦截器对于创建整个应用层面的可复用方案有非常大的意义。比如说,我们需要将所有响应中出现的
@Injectable()
export class ExcludeNullInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(map(value => (value === null ? "" : value)));
}
}
异常映射
另外一个有趣的用例是使用
@Injectable()
export class ErrorsInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next
.handle()
.pipe(catchError(err => throwError(new BadGatewayException())));
}
}
流重写
有一些情况下我们希望完全阻止处理器的调用并返回一个不同的值。比如缓存的实现。让我们来试试使用缓存拦截器来实现它。当然真正的缓存实现还包含
@Injectable()
export class CacheInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const isCached = true;
if (isCached) {
return of([]);
}
return next.handle();
}
}
上面的代码中我们硬编码了
更多的操作符
@Injectable()
export class TimeoutInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(timeout(5000));
}
}