icon안동민 개발노트

미들웨어 사용


 Next.js의 미들웨어 기능은 요청이 완료되기 전에 코드를 실행할 수 있게 해주는 강력한 도구입니다.

 이 절에서는 미들웨어의 기본 개념, 사용 사례, 그리고 API 라우트와의 통합에 대해 알아보겠습니다.

미들웨어 기본 개념

 미들웨어는 요청이 서버에 도달하기 전에 실행되는 함수입니다.

 이를 통해 요청을 수정하거나, 응답을 조작하거나, 리다이렉션을 수행할 수 있습니다.

미들웨어 파일 생성 및 구성

 Next.js에서 미들웨어를 사용하려면 프로젝트 루트에 middleware.js 또는 middleware.ts 파일을 생성합니다.

middleware.js
import { NextResponse } from 'next/server'
 
export function middleware(request) {
  // 미들웨어 로직
  return NextResponse.next()
}

요청/응답 수정

 미들웨어에서 요청이나 응답을 수정할 수 있습니다.

export function middleware(request) {
  // 요청 헤더 수정
  const requestHeaders = new Headers(request.headers)
  requestHeaders.set('x-hello-from-middleware', 'hello')
 
  // 응답 헤더 수정
  const response = NextResponse.next({
    request: {
      headers: requestHeaders,
    },
  })
  response.headers.set('x-hello-from-middleware', 'hello')
 
  return response
}

리다이렉션 처리

 특정 조건에 따라 사용자를 다른 페이지로 리다이렉트할 수 있습니다.

import { NextResponse } from 'next/server'
 
export function middleware(request) {
  if (request.nextUrl.pathname.startsWith('/old-blog')) {
    return NextResponse.redirect(new URL('/blog', request.url))
  }
}

조건부 미들웨어 실행

 특정 경로에 대해서만 미들웨어를 실행하고 싶다면 matcher 설정을 사용할 수 있습니다.

export function middleware(request) {
  // 미들웨어 로직
}
 
export const config = {
  matcher: '/api/:path*',
}

 이 설정은 /api/ 로 시작하는 모든 경로에 대해서만 미들웨어를 실행합니다.

API 라우트와의 통합

 미들웨어는 API 라우트에도 적용됩니다.

 예를 들어, API 요청에 대한 인증을 처리할 수 있습니다.

import { NextResponse } from 'next/server'
 
export function middleware(request) {
  if (request.nextUrl.pathname.startsWith('/api/')) {
    if (!request.headers.get('Authorization')) {
      return new NextResponse(
        JSON.stringify({ error: 'Authentication required' }),
        { status: 401, headers: { 'Content-Type': 'application/json' } }
      )
    }
  }
  return NextResponse.next()
}

10장 인증 및 권한 관리와의 연결

 미들웨어는 10장에서 다룬 인증 및 권한 관리와 밀접하게 연관됩니다.

 미들웨어를 사용하여 모든 요청에 대해 인증을 확인하고, 인증되지 않은 사용자를 로그인 페이지로 리다이렉트하거나 특정 API 엔드포인트에 대한 접근을 제한할 수 있습니다.

 예를 들어,

import { NextResponse } from 'next/server'
import { getToken } from 'next-auth/jwt'
 
export async function middleware(request) {
  const token = await getToken({ req: request, secret: process.env.JWT_SECRET })
 
  if (!token && request.nextUrl.pathname.startsWith('/api/protected')) {
    return new NextResponse(
      JSON.stringify({ error: 'Authentication required' }),
      { status: 401, headers: { 'Content-Type': 'application/json' } }
    )
  }
 
  return NextResponse.next()
}

실습 : API 로깅 및 인증 체크 미들웨어

 API 요청에 대한 로깅과 기본적인 인증 체크를 수행하는 미들웨어를 구현해보겠습니다.

middleware.js
import { NextResponse } from 'next/server'
 
export function middleware(request) {
  // 1. 로깅
  console.log(`[${new Date().toISOString()}] ${request.method} ${request.url}`)
 
  // 2. API 요청에 대한 기본 인증 체크
  if (request.nextUrl.pathname.startsWith('/api/')) {
    const authHeader = request.headers.get('Authorization')
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      return new NextResponse(
        JSON.stringify({ error: 'Authentication required' }),
        { status: 401, headers: { 'Content-Type': 'application/json' } }
      )
    }
 
    // 여기서는 간단히 토큰 존재 여부만 확인합니다.
    // 실제 애플리케이션에서는 토큰 유효성을 검증해야 합니다.
    const token = authHeader.split(' ')[1]
    if (!token) {
      return new NextResponse(
        JSON.stringify({ error: 'Invalid token' }),
        { status: 401, headers: { 'Content-Type': 'application/json' } }
      )
    }
 
    // 토큰이 유효하다고 가정하고, 요청에 사용자 정보를 추가합니다.
    const requestHeaders = new Headers(request.headers)
    requestHeaders.set('x-user-id', 'user_123') // 실제로는 토큰에서 추출한 사용자 ID를 사용해야 합니다.
 
    return NextResponse.next({
      request: {
        headers: requestHeaders,
      },
    })
  }
 
  // API 요청이 아닌 경우 그대로 통과
  return NextResponse.next()
}
 
export const config = {
  matcher: [
    /*
     * Match all request paths except for the ones starting with:
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     */
    '/((?!_next/static|_next/image|favicon.ico).*)',
  ],
}

 이 미들웨어는 다음과 같은 기능을 수행합니다.

  1. 모든 요청에 대해 메서드, URL, 시간을 로깅합니다.
  2. /api/로 시작하는 모든 요청에 대해 기본적인 인증 체크를 수행합니다.
  3. 유효한 Bearer 토큰이 없는 API 요청을 거부합니다.
  4. 인증된 요청에 대해 사용자 ID를 헤더에 추가합니다.

 이 실습을 통해 미들웨어를 사용하여 API 요청을 로깅하고 기본적인 인증을 구현하는 방법을 익힐 수 있습니다.

 실제 애플리케이션에서는 더 복잡한 인증 로직과 토큰 검증이 필요할 것입니다.

 Next.js의 미들웨어는 애플리케이션의 보안, 로깅, 라우팅 제어 등 다양한 용도로 활용될 수 있는 강력한 기능입니다.

 API 라우트와 결합하여 사용하면 더욱 유연하고 안전한 백엔드 로직을 구현할 수 있습니다.