개발 학습일지(TIL)

TIL : Nestjs, 특정 페이지(URL) 접근만 미들웨어 예외 처리

Veams 2023. 3. 13.

nest.js 및 ejs 템플릿 엔진 사용환경.

 

- nestjs를 사용하는 이번 팀 프로젝트에서는 클라이언트 사이드에서 페이지 렌더링을 위해 반복적으로 사용되는 코드를 줄이고, 유지보수성을 높이기 위하여 express-ejs-layouts 라이브러리를 사용하기로 하였다.

- 이 라이브러리를 사용하기 위하여 기존에는 app.use 전역 미들웨어를 선언하며 header와 footer 부분을 처리하였다.

 

기존의 코드 및 화면 상태

//main.ts

import { ValidationPipe } from '@nestjs/common';
import { NestExpressApplication } from '@nestjs/platform-express';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module'
import { join } from 'path';
const ejslayouts = require('express-ejs-layouts')

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(
    AppModule
  );

  app.useGlobalPipes(new ValidationPipe({ transform: true }));

  //express-ejs-layouts 설정
  app.use(ejslayouts);
  app.set('layout', 'layouts/main.ejs');

  //ejs 셋팅
  app.useStaticAssets(join(__dirname, "../", "views", "public")); //static폴더를 현재폴더(dirname)에서 한칸 상위('..')에 있는 views/public 폴더로 지정
  app.setBaseViewsDir(join(__dirname, "../", "views")); //view폴더 지정 :현재폴더(dirname)에서 한칸 상위('..')에 있는 views폴더로 지정
  app.setViewEngine("ejs"); //view엔진을 ejs로 셋팅

  const PORT = process.env.PORT;

  await app.listen(PORT, function () {
    console.log(`서버가 ${PORT} 포트로 열렸습니다. http://localhost:${PORT}`);
  });
}
bootstrap();

 

//main.ejs 일부


<body>
    <div class="container-xxl px-md-5 bg-white shadow-lg">
        <%- include("header.ejs") %>

        <main><%- body %></main>
        
        <%- include("footer.ejs") %>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>
</body>

</html>

 

문제상황 : 어떻게 하면 원하는 페이지에서만 미들웨어를 작동시킬 수 있을까?

- 로그인/회원가입 페이지를 작업하는 팀원이, 로그인 및 회원가입 페이지에 header, footer를 적용하고 싶지 않다고 하면서, express-ejs-layouts 라이브러리를 사용하는 대신 ejs 템플릿 엔진만 사용하는 것을 제안하였다.

- 내가 express-ejs-layouts를 이번 프로젝트에 도입한 이유가 렌더링 페이지에 포함되는 layout 코드들에 대해 유지보수를 편하게 하기 위해서였다.

- 만약, 이 라이브러리를 사용하지 않고 ejs템플릿 엔진만 적용하는 경우에는 모든 페이지마다 header와 footer를 include 하는 코드를 넣어야 해서, 반복 코드가 생길 뿐만 아니라, 작업할 페이지가 많아져서 각 페이지의 작업자가 개발에 불편할 것이 예상되었다. 이 경우, 유지보수성을 어느 정도 포기해야하는 상황이 발생한다.

 

시도 1

- 로그인 페이지에 header, footer를 포함시키는 것은 어떨까? 의문이 생겼다. 그래서 다른 웹 서비스들은 어떻게 구현하나 살펴봤더니, 11번가, 롯데온 같은 페이지에서는 로그인 창만 깔끔하게 구현해 놓은 것을 확인할 수 있었다. 더 깔끔해 보이긴 했다.

 

 

- 그래서 이 라이브러리를 사용하면서도 로그인페이지만 예외적으로 express-ejs-layouts 라이브러리를 적용하지 않는 방법을 고민하게 되었다.

 

시도 2

- express-ejs-layouts는 기본적으로 전역 미들웨어로 선언하여 사용한다. app.use()를 사용한다. 그래서 sign 로그인 페이지에 한정해서 미들웨어를 통과하지 않도록 설정하면 되지 않을까라는 상상을 하게 되었다.

- 그래서 nestjs에서는 미들웨어 사용하는 법을 탐색하였는데, nest.js에서는 특정 API에 대해서는 미들웨어 적용을 제외시키는 방법이 있었다. 바로 이 방법을 사용하면 뭔가 변화가 있을지 않을까 기대를 하였다.

 

해법 : nestjs 특정 모듈에서 미들웨어 적용하기, 동시에 exclude() 메쏘드 사용하기  

기존 main.ts에서 설정해 준 app.use() 대신, app.module.ts에서 미들웨어를 사용하는 방법이 있다. 다음 코드블록의 하단의 exprt class로 시작하는 부분을 살펴보자.

 

//app.module.ts

const ejsMiddleware = require("express-ejs-layouts");

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      useClass: typeOrmConfigService,
      inject: [ConfigService],
    }),
    JwtModule.registerAsync({
      imports: [ConfigModule],
      useClass: JwtConfigService,
      inject: [ConfigService],
    }),

    EventModule,
    SearcherModule,
    ClubModule,
    UserpageModule,
    AuthModule,
    RedisModule,
  ],
  controllers: [AppController],
  providers: [],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(ejsMiddleware)
      .exclude(
        { path: "sign", method: RequestMethod.GET },
        { path: "sign", method: RequestMethod.POST },
        "sign/(.*)",
      )
      .forRoutes("/");
  }
}

 

.apply(ejsMiddleaware) 키워드로 사용할 express-ejs-layouts를 기재하였고,

.exclude() 메쏘드를 통해서 로그인 페이지인 /sign URL로 접속할  경우, GET과 POST http 메쏘드에 한정하여 미들웨어가 적용되지 않도록 명령하였다.

 

적용 결과

 

알게 된 점.

express에서 사용하던 경험을 토대로, app.use로 전역 미들웨어 사용하는 방법만 알고 있었는데 nestjs에서는 미들웨어를 활용하는 간단한 방법이 있었다.

 

특정 페이지만 미들웨어를 적용하거나, 혹은 적용하지 않고자 한다면,  nestjs에서 생성한 모듈에서 미들웨어를 적용하는 방법을 적극 활용하자. 프레임워크가 있으니 확실히 편안하다는 것을 느꼈다.

 

 

참고 문서

https://www.wisewiredbooks.com/nestjs/overview/06-middleware.html

 

미들웨어 - 쉽게 풀어 쓴 Nest.js

미들웨어는 클라이언트로부터 들어온 요청을 각 컨트롤러의 요청 핸들러가 처리하기 이전에 코드를 실행할 수 있는 기능입니다. 미들웨어 함수는 애플리케이션의 요청-응답 주기에서 요청(reque

www.wisewiredbooks.com

 

댓글