-
Nest.js 커스텀 Middleware 만들기FrameWork/Nest.js 2022. 8. 4. 17:00
Request와 Response 변수를 사용하는 경우
@ApiResponse({ status: 200, description: '성공', type: UserDto, }) @ApiOperation({ summary: '로그인' }) @Post('login') login(@Req() req) { return req.user; }
웬만하면 Request와 Response 객체는 사용하지 않는 것이 좋다. 그렇게 되면 어떤 특정한 플랫폼에 종속되서 나중에 바꾸기도 어려워지고 test하기도 어려워진다.
보통 express의 경우 res.locals.jwt에 jwt token을 많이 넣는다. express에서는 res.locals가 middleware간에 공유할 수 있느 변수 역할을 해주기 때문이다.
custorm decorator를 사용하면 request혹은 response를 직접적으로 사용하지 않을 수 있다.
🔔Middleware Function
function(req,res,next){ res.send(....) }
미들웨어 함수는 요청 오브젝트(req),응답 오브젝트(res) 그리고 app의 요청-응답 주기 중 그 다음의 미들웨어 함수에 대한 access 권함을 갖는 함수이다. 그 다음에 미들웨어 함수는 이반적으로 next라는 이름의 변수로 표시된다.
- 모든 코드를 실행
- 요청 및 응잡 오브젝트에 대한 변경을 실행
- 요청-응답 주기를 종료
- 스택 내의 그 다음 미들웨어를 호출
현재의 미들웨어 함수가 요청 응답 주기를 종료하기 않는 경우에는 next()를 호출하여 그 다음 미들웨어 함수에 제어를 전달해야 한다. 그렇지 않으면 해당 app 요청에서 정지된 채로 방치된다.
LoggerMiddleware
import { Injectable, Logger, NestMiddleware } from '@nestjs/common'; import { NextFunction, Request, Response } from 'express'; @Injectable() export class LoggerMiddleware implements NestMiddleware { private logger = new Logger('HTTP'); use(request: Request, response: Response, next: NextFunction): void { const { ip, method, originalUrl } = request; const userAgent = request.get('user-agent') || ''; response.on('finish', () => { const { statusCode } = response; const contentLength = response.get('content-length'); this.logger.log( `${method} ${originalUrl} ${statusCode} ${contentLength} - ${userAgent} ${ip} `, ); }); next(); } }
implements 같은 경우는 반드시 구현을 해야하는 강제사항이 생긴다. NestMiddleware같은 경우는 user()라는 메서드를 반드시 구현해야한다.
nest를 할 때는 console.log()보다 this.logger.log()( Logger.log())를 많이 사용한다.
🔔middleware를 사용할 때는 항상 response로 응답을 보내거나 next()메서드를 사용해서 다음 middleware chain으로 넘겨준다.
response.on()
LoggerMiddleware자체는 router보다 먼저 실행이된다. 이와 다르게 morgan은 router가 끝나고 logging을 해준다. 그렇기 때문에 router가 실행되기 전에 request에 관련한 것을 기록하고 나서 response에 대한것은 router가 끝나고 finish 이벤트가 시작 할때 기록을 해주기 때문에 response.on()은 비동기로 빠져있다.
실행순서
Context 부여
private logger = new Logger('HTTP');
Logger 생성자 안에 괄호의 'HTTP'는 context를 부여해준 것이다.
context가 어떤 역할을 설명하자면 다음과 같다. =>
백엔드 개발을 하다보면 console.log가 엄청나게 많이 쌓이는데, 서로 다른 함수에서 나온 console.log()끼리 서로 섞여서 번갈아 가다 출력되게 되면, console.log()가 너무 많아져서 추적이 힘들어진다.
console.log()가 그냥 log로 찍힐 뿐이지 해당 log가 어떤 메소드나 로직으로 부터 파생된 것 인지 출처를 알기힘들다. 이런 단점을 극복하기 위해서 debug라는 package를 많이 사용한다. log 앞에다가 특정 글자를 붙여줘서 어떤 console.log()가 어떤 문맥에서 발생한것 인지 알 수있게 해주는 npm package이다.
https://www.npmjs.com/package/debug
NestJS의 경우 logger 인스턴스 변수를 생성할때 context를 지정해주면 지정된 context에 대한 log는 ~~~하게 보여진다.
LoggerMiddleware 사용하기위해 연결
export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(LoggerMiddleware).forRoutes('*'); } }
forRoutes(컨트롤러이름) 혹은 forRoutes(주소)와 같이 표기해서 특정 주소에만 middleware 적용이 가능하다.
@Module()에서는 middleware를 위한 consumer로써의 사용을 표시하기 위한 공간이 없기 때문에 configure() module의 메서드를 사용해서 middleware 사용을 표시해주어야 한다. 또한 middleware를 consumer가 되는 module은 NestModule 인터페이스를 구현해야한다.
apply메서드 뒤에 체인으로 붙은 .forRotues()메서드는 특정 router에 바인딩을 위한 것으로 특정 module의 entry point가되는 URL 키워드를 넣으면 해당 module과 middleware가 바인딩된다. 위 코드 처럼 와일드카드를 사용하면 전체 URL의 entry poin에 apply 메소드의 인자로 들어간 middleware를 바인딩 한다는 의미이다.
log출력 결과
'FrameWork > Nest.js' 카테고리의 다른 글
Nest.js Interceptors 사용하기 (0) 2022.08.07 Next.js custom decorator만들기 (0) 2022.08.07 Multer와 미디어 파일 서비스(img,mp3,mp4) 1 (0) 2022.07.30 Nest.js Intercepters(AOP 패턴) (0) 2022.07.24 Nest.js Pipes(변환, 유효성 검사) (0) 2022.07.11