๐ŸŽ‰ berenickt ๋ธ”๋กœ๊ทธ์— ์˜จ ๊ฑธ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค. ๐ŸŽ‰
Back
NestJs
30-middleware

1. Middleware ์ด๋ก 

nestjs-request-life-cycle

  1. Request
  2. Middleware
    • Global Middleware
    • Module Middleware
  3. Guard
    • Global Guards
    • Controller Guards
    • Route Guards
  4. Interceptors
    • Global Interceptors
    • Controller Interceptors
    • Route Interceptors
  5. Pipes
    • Global Pipes
    • Controller Pipes
    • Route Pipes
    • Route Parameter Pipes
  6. Controller
  7. Service
  8. Interceptor
    • Router Interceptor
    • Controller Interceptor
    • Global Interceptor
  9. Exception Filters
    • Route
    • Controller
    • Global
  10. Response

๋ฏธ๋“ค์›จ์–ด๋Š” ๊ฐ€์žฅ ์‰ฝ๊ณ  ๊ฐ€์žฅ ๋‹จ์ˆœํ•˜๊ณ  ๊ฐ€์žฅ ์–ด๋–ป๊ฒŒ ๋ณด๋ฉด ์›์ดˆ์ ์ธ ๊ธฐ๋Šฅ์ด๋‹ค.

Middlewares_1

  • ๊ณต์‹๋ฌธ์„œ : https://docs.nestjs.com/middleware
  • ์œ„ ๊ทธ๋ฆผ์„ ๋ณด๋ฉด, ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์—์„œ ์š”์ฒญ์„ ๋„ฃ๊ณ , ๋ผ์šฐํŠธ ํ•ธ๋“ค๋Ÿฌ๊นŒ์ง€ ๊ฐ€๊ธฐ ์ „์— ๋ฏธ๋“ค์›จ์–ด๋ฅผ ๊ฑฐ์นœ๋‹ค.
  • ์ „์ฒด ๊ทธ๋ฆผ์„ ๋ดค์„ ๋•Œ๋„, ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ๊ฐ€์žฅ ๋จผ์ € ์š”์ฒญ์„ ๋ฐ›๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

Middleware๋Š” ๋ผ์šฐํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์‹คํ–‰๋œ๋‹ค. Request์™€ Response ๊ฐ์ฒด์— ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

Middleware๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์ž์œ ๋กญ๊ฒŒ ์ฝ”๋“œ ์‹คํ–‰
  • ์š”์ฒญ๊ณผ ์‘๋‹ต ๊ฐ์ฒด๋ฅผ ๋ณ€๊ฒฝ
  • ์š”์ฒญ ์‘๋‹ต ์‚ฌ์ดํด ์ค‘๋‹จ
  • ๋‹ค์Œ ๋ฏธ๋“ค์›จ์–ด ์‹คํ–‰ํ•˜๊ธฐ

1.1 Middleware๋ž€?

Nest ๋ฏธ๋“ค์›จ์–ด๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Express ๋ฏธ๋“ค์›จ์–ด์™€ ๋™์ผํ•˜๋‹ค. ๊ณต์‹ ๋ฌธ์„œ์˜ ๋‹ค์Œ ์„ค๋ช…์€ ๋ฏธ๋“ค์›จ์–ด์˜ ๊ธฐ๋Šฅ์„ ์„ค๋ช…ํ•œ๋‹ค.

๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜๋Š” ๋‹ค์Œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • execute any code (์–ด๋–ค ์ฝ”๋“œ๋“  ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.)
  • make changes to the request and the response objects.
    • ์š”์ฒญ ๋ฐ ์‘๋‹ต ๊ฐ์ฒด์˜ ๋ณ€ํ™”๋ฅผ ๋งŒ๋“ค์–ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.
    • ๋ฌด์–ธ๊ฐ€๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œ, ์—…๋ฐ์ดํŠธ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ
  • end the request-response cycle.
    • ์š”์ฒญ์ด ๋๋‚˜๊ฒŒ ์ค‘๊ฐ„์— ์ค‘์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ผ์ข…์˜ guard ์—ญํ• ๋„ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ
  • call the next middleware function in the stack.
    • ์Šคํƒ์—์„œ ๋‹ค์Œ ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํžŒ๋‹ค.
    • ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ ์šฉ๋œ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰๋œ๋‹ค.
    • ์ฆ‰, ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ์—ฎ์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ
  • if the current middleware function does not end the request-response cycle,
  • it must call next() to pass control to the next middleware function.
  • Otherwise, the request will be left hanging.
    • ํ˜„์žฌ ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜๊ฐ€ ์š”์ฒญ-์‘๋‹ต ์ฃผ๊ธฐ๋ฅผ ์ข…๋ฃŒํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, (=> ์—๋Ÿฌ๋ฅผ ๋˜์ง€์ง€ ์•Š๋Š”๋‹ค๋ฉด,)
    • ๋‹ค์Œ ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜์— ์ œ์–ด๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด next() ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.
    • ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์š”์ฒญ์ด ์ค‘๋‹จ๋œ ์ƒํƒœ๋กœ ๋‚จ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

2. Middleware ์‚ฌ์šฉ๋ฒ•

2.1 Middleware ์„ ์–ธ๋ฒ•

1
import { Injectable, NestMiddleware } from '@nestjs/common'
2
import { Request, Response, NextFunction } from 'express'
3
4
@Injectable()
5
export class LogMiddleware implements NestMiddleware {
6
use(req: Request, res: Response, next: NextFunction) {
7
console.log(`[REQ] ${req.method} ${req.url} ${new Date().toLocaleString('kr')}`)
8
next()
9
}
10
}

2.2 Middleware ์ ์šฉ๋ฒ•

์ ์šฉ๋ฒ• 1 : ๋ชจ๋“ˆ์— ์ ์šฉ

1
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common'
2
import { LoggerMiddleware } from './common/middleware/logger.middleware'
3
import { CatsModule } from './cats/cats.module'
4
5
@Module({
6
imports: [CatsModule],
7
})
8
export class AppModule implements NestModule {
9
configure(consumer: MiddlewareConsumer) {
10
consumer.apply(LoggerMiddleware).forRoutes('cats')
11
}
12
}
1
import { Module, NestModule, RequestMethod, MiddlewareConsumer } from '@nestjs/common'
2
import { LoggerMiddleware } from './common/middleware/logger.middleware'
3
import { CatsModule } from './cats/cats.module'
4
5
@Module({
6
imports: [CatsModule],
7
})
8
export class AppModule implements NestModule {
9
configure(consumer: MiddlewareConsumer) {
10
consumer.apply(LoggerMiddleware).forRoutes({ path: 'cats', method: RequestMethod.GET })
11
}
12
}

์ ์šฉ๋ฒ• 2 : ์ปจํŠธ๋กค๋Ÿฌ์— ์ ์šฉ

1
forRoutes({ path: 'cats', method: RequestMethod.ALL })
1
consumer
2
.apply(LoggerMiddleware)
3
.exclude(
4
{ path: 'cats', method: RequestMethod.GET }, //
5
{ path: 'cats', method: RequestMethod.POST },
6
'cats/(.*)',
7
)
8
.forRoutes(CatsController)
1
consumer.apply(cors(), helmet(), logger).forRoutes(CatsController)

์ ์šฉ๋ฒ• 3 : ๊ธ€๋กœ๋ฒŒ ๋ฏธ๋“ค์›จ์–ด์— ์ ์šฉ

1
const app = await NestFactory.create(AppModule)
2
app.use(logger)
3
await app.listen(3000)

3. Middleware ์‚ฌ์šฉ

common/middleware/log.middleware.ts ํŒŒ์ผ์„ ๋งŒ๋“ ๋‹ค.

common/middleware/log.middleware.ts
1
import { Injectable, NestMiddleware } from '@nestjs/common'
2
import { NextFunction } from 'express'
3
4
@Injectable()
5
export class LogMiddleware implements NestMiddleware {
6
use(req: Request, res: Response, next: NextFunction) {
7
console.log(`[REQ] ${req.method} ${req.url} ${new Date().toLocaleString('kr')}`)
8
next()
9
}
10
}

์ •ํ™•ํ•œ ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด posts ์ปจํŠธ๋กค๋Ÿฌ์— ์ ์šฉํ•œ Interceptors์™€ Filter๋ฅผ ์ฃผ์„์ฒ˜๋ฆฌํ•œ๋‹ค.

posts.controller.ts
1
/*** 1) GET /posts
2
* ๋ชจ๋“  post๋ฅผ ๋‹ค ๊ฐ€์ ธ์˜จ๋‹ค
3
*/
4
@Get()
5
// @UseInterceptors(LogInterceptor)
6
// @UseFilters(HttpExceptionFilter)
7
getPosts(@Query() query: PaginatePostDto) {
8
// throw new BadRequestException('์—๋Ÿฌ ํ…Œ์ŠคํŠธ')
9
return this.postsService.paginatePosts(query)
10
}

๋ฏธ๋“ค์›จ์–ด๋Š” ๋ชจ๋“ˆ์—๋‹ค๊ฐ€ ์ ์šฉํ•ด์•ผ ํ•œ๋‹ค. posts ๋ชจ๋“ˆ์— ์œ„์— ์ž‘์„ฑํ•œ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ ์šฉํ•œ๋‹ค.

posts.module.ts
1
// posts.module.ts ์ƒ๋žต
2
export class PostsModule implements NestModule {
3
configure(consumer: MiddlewareConsumer) {
4
consumer.apply(LogMiddleware).forRoutes({
5
path: 'posts*', // posts ๋’ค์— ์–ด๋–ค ๊ธ€์ž์ด๋“  ์ ์šฉ(์™€์ผ๋“œ์นด๋“œ)
6
// method: RequestMethod.ALL, // ๋ชจ๋“  ์š”์ฒญ์— ์ ์šฉ
7
method: RequestMethod.GET, // GET ์š”์ฒญ๋งŒ ์ ์šฉ
8
})
9
}
10
}

๊ทธ๋Ÿฐ๋ฐ ์ด๋ ‡๊ฒŒ ํŠน์ • ๋ชจ๋“ˆ์—๋งŒ ์•„๋‹ˆ๋ผ ๋ชจ๋“  ๋ชจ๋“ˆ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์œ„์—์„œ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์›๋ž˜๋Œ€๋กœ export class PostsModule{}๋งŒ ๋‚จ๊ธด๋‹ค.
  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์•ฑ ์ „์ฒด ๋ชจ๋“  ๋ผ์šฐํŠธ์— ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ ์šฉํ•ด, ์š”์ฒญ์— ๋กœ๊ทธ๋ฅผ ์ฐ์„ ์ˆ˜ ์žˆ๋‹ค.
  • ๋Œ€์šฉ๋Ÿ‰ ํŠธ๋ž˜ํ”ฝ์ด ๋“ค์–ด์˜ค๋Š” ํŠธ๋ž˜ํ”ฝ๋“ค์„ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์„ ๋ฏธ๋“ค์›จ์–ด๋กœ ๋งŒ๋“ค๋ฉด ์œ ์šฉํ•˜๋‹ค.
app.module.ts
1
// app.module.ts ์ƒ๋žต
2
export class AppModule implements NestModule {
3
configure(consumer: MiddlewareConsumer) {
4
consumer.apply(LogMiddleware).forRoutes({
5
path: '*', // ๋’ค์— ์–ด๋–ค ๊ธ€์ž์ด๋“  ์ ์šฉ(์™€์ผ๋“œ์นด๋“œ)
6
method: RequestMethod.ALL, // ๋ชจ๋“  ์š”์ฒญ์— ์ ์šฉ
7
})
8
}
9
}