Почему перехватчик nestjs возвращает значение undefined?

#javascript #node.js #typescript #interceptor #nestjs

#javascript #node.js #typescript #перехватчик #nestjs

Вопрос:

Я пытаюсь реализовать перехватчик ведения журнала в 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$ operator ведет себя как Observable и что nestjs будет внутренне подписан на отправку ответа клиенту, но я хотел записать информацию перед отправкой и, возможно, преобразовать ответ

Итак, я использую оператор map() в rxjs. Это работает должным образом, если набор ответов имеет тип, отличный от ‘application / json’. Если тип содержимого имеет значение ‘plain / text’, применяется операция сопоставления, которая преобразуется в желаемый объект json и отправляется клиенту, но не в том случае, если ответ уже имеет тип application / json, то есть объект json. Я не могу применить объект transform. При регистрации значения, отправленного в 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');
}
  

Комментарии:

1. Пожалуйста, добавьте свой контроллер, с помощью которого можно воспроизвести вашу проблему. Вы внедряете @Res() в свой контроллер?

2. @KimKern Я также добавил контроллер

Ответ №1:

Когда вы вводите @Res() в свой метод контроллера, многие функции, которые делают nest такими замечательными, как перехватчики, не будут работать.


В большинстве случаев вам не нужно вводить @Res() , потому что вместо этого вы можете использовать выделенные декораторы. В вашем примере это было бы:

 // Sets the http response code (default for POST is 201, for anything else 200)
@HttpCode(204)
// Sets a custom header
@Header('SampleHeader', 'somevalue')
@Get('/getTest/:id1/:id2')
public getConfigDataInResponse(@Param('id1') id1: number, @Param('id2') id2: number) {
  return 'some data';
}
  

Комментарии:

1. Спасибо, Ким. Я подозревал, что это может не сработать, поскольку я использовал @Res, но не уверен, так ли это. Спасибо за подтверждение. Вы спаситель с запросами nestjs.

2. @Kim Я нахожусь в аналогичной ситуации, когда мне нужно добавить пользовательские заголовки в ответ, но я также хочу использовать перехватчик, где мне нужно добавить несколько дополнительных полей в тело ответа. Есть ли способ в перехватчиках, с помощью которого я могу достичь обоих этих результатов?