【发布时间】:2019-08-07 20:44:07
【问题描述】:
我正在尝试在nestjs 中实现一个日志拦截器,以便它捕获所有请求和响应并将其记录下来。
因此我实现了这样的 LoggingInterceptor
import { logger } from './../utils/logger';
import { ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable, BehaviorSubject, from } from 'rxjs';
import { map, tap, refCount, publish, publishLast } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptorInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, call$: Observable<any>): Observable<any> {
const reqHeaders = context.switchToHttp().getRequest().headers;
const reqBody = context.switchToHttp().getRequest().body;
logger.info('Logging the incoming request:',reqHeaders);
logger.info('Logging the incoming req body:', reqBody);
const now = Date.now();
logger.info('Time of request call is', now);
const serviceBehaviorSubj = new BehaviorSubject<any>(null);
// response will be available only in the call$ observable stream
// so use tap to get a clone of the observable and print the data sent
// this pipe call transforms the response object to start with something called data
// so a default response like "Done", "test" looks now as a json string
// {data : Done} {data: test}
// const anotherrespObs: Observable<any> = call$.pipe(publishLast(), refCount());
// anotherrespObs.pipe(publishLast(), refCount()).subscribe(data => {
// logger.info('Logging the outgoing response', data);
// });
return call$.pipe(map(data => {
console.log('data here is', data);
return ({ dottted: data });
}));
//oo.then(return new Pro)
// return call$.pipe(tap(() => {
// logger.info(`Time of completion is ${Date.now() -now}`);
// }), map(data => {
// console.log('ccccccc', data);
// return data;
// }));
}
}
我知道 call$ 操作符的行为类似于 Observable 并且将由 nestjs 在内部订阅以将响应发送给客户端,但我想在发送之前记录信息并可能转换响应
所以我使用了 rxjs 的 map() 操作符。如果响应集的类型不是“application/json”,则此功能正常。如果内容类型 是“纯文本”,映射操作被应用并转换为所需的 json 对象并发送到客户端,但如果响应已经是 application/json 类型,即 json 对象,则不会。我无法应用变换对象。在记录发送到 map() 的值时,我看到它被记录为 json 对象的未定义。那么我如何获得响应(即使它是一个 json 对象)并可能在将其发送到拦截器中的客户端之前对其进行记录和转换
注意:我担心响应可能包含敏感信息,但我可能会使用日志屏蔽来屏蔽响应数据,但这目前用于测试目的
这是我能够在拦截器中记录响应的示例控制器
@ApiOperation({ title: 'Get - With Params', description: 'Test Method with parms' })
@Get('/getTest/:id1/:id2')
@ApiOkResponse({ description: 'Sample string is emitted' })
@ApiResponse({ status: 404, description: 'The endpoint is unavailable' })
@ApiResponse({ status: 503, description: 'The endpoint cannot be processed' })
// @Header('sampleHeaderKey', 'sampleHeaderValue')
// NOte if you send params in the URL and do not use @param then the URL will
// result in NO such end point
public getConfigDataInResponse(@Param('id1') id1: number, @Param('id2') id2: number, @Req() req) {
logger.info('request headers', req.headers);
logger.info('reqiest params', req.params);
logger.info('reqiest query params', req.query);
logger.info('reqiest body ', req.body);
return 'TEST';
}
这是无法记录响应的方法,它在拦截器中显示为“未定义”
public getConfigDataInResponse(@Param('id1') id1: number, @Param('id2') id2: number, @Req() req, @Res() res) {
logger.info('request headers', req.headers);
logger.info('reqiest params', req.params);
logger.info('reqiest query params', req.query);
logger.info('reqiest body ', req.body);
res.set('SampeHeader', 'saomevaluie');
res.status(HttpStatus.OK).send('some data');
}
【问题讨论】:
-
请添加您的控制器以重现您的问题。你在控制器中注入
@Res()吗? -
@KimKern 我也添加了控制器
标签: javascript node.js typescript interceptor nestjs