Middleware

Odyssey·2025년 3월 31일
0

Next.js_study

목록 보기
43/58
post-thumbnail

2025.3.31 월요일의 공부기록

이 글에서는 Next.js에서 미들웨어(Middleware) 가 무엇인지, 어떤 상황에서 사용하면 좋은지 구체적인 사례와 함께 살펴본다. 또한 실제 프로젝트에서 미들웨어를 적용하는 실습 코드와 함께 Fetch API의 Response 인터페이스에 대해서도 간단히 알아본다.


미들웨어(Middleware)란?

미들웨어는 사용자의 요청(request)이 서버에서 최종적으로 처리되기 전에 중간에서 실행되는 코드이다. 즉, Next.js에서 미들웨어는 요청이 라우팅되어 페이지나 API에 도달하기 전에 개입하여 추가 작업을 수행할 수 있다.

특히 Next.js의 미들웨어는 아래와 같은 모든 요청에서 실행된다:

  • HTML 페이지
  • API 요청
  • 이미지, CSS, JS, Favicon 등 정적 자원 요청

이러한 특성 덕분에 인증 처리, 권한 부여, 서버 사이드 리다이렉트 등 다양한 용도로 활용할 수 있다.

📌 Next.js Middleware 공식 문서


미들웨어의 주요 사용 케이스

미들웨어를 활용하는 대표적인 사례는 다음과 같다:

  1. 인증 및 권한 부여
    • 사용자 인증 상태를 확인하여 특정 페이지나 API에 대한 접근을 제어한다.
  2. 서버 사이드 리다이렉션
    • 요청 조건에 따라 서버에서 사용자를 다른 페이지로 강제로 이동시킨다.
  3. 경로 재작성(Rewriting)
    • A/B 테스트, 기능 출시(Feature Flags) 등 요청을 동적으로 다른 페이지나 API로 재구성할 때 사용한다.
  4. 봇 탐지 및 보호
    • 자동화된 봇 접근을 탐지하고 차단하여 서버 자원을 보호한다.
  5. 로깅 및 분석
    • 모든 요청을 기록하여 분석 및 로그 데이터를 축적한다.
  6. 기능 플래그(Feature Flags)
    • 특정 사용자 그룹이나 조건에 따라 기능의 활성화 여부를 관리한다.

Middleware 사용 사례 자세히 보기


실습: Next.js에서 미들웨어 구현하기

예시 코드 (middleware.ts)

아래 예시 코드는 로그인 상태 확인 후, 특정 페이지(/profile)에 접근을 시도하면 메인 페이지로 리다이렉트하는 간단한 미들웨어이다.

// middleware.ts
import { NextRequest, NextResponse } from "next/server";
import { getSession } from "@/lib/session";

export async function middleware(request: NextRequest) {
  const session = await getSession();
  console.log(session);

  // 사용자가 "/profile" 경로에 접근 시 메인 페이지로 리다이렉트 처리
  if (request.nextUrl.pathname === "/profile") {
    return NextResponse.redirect(new URL("/", request.url));
  }

  // 별도의 처리가 필요 없는 경우, undefined를 반환하면 정상적으로 페이지가 렌더링됨
}

코드 상세 설명

  • NextRequest: Next.js가 제공하는 요청 객체로, 요청에 대한 다양한 정보를 담고 있다.
  • NextResponse: Next.js의 응답 객체로, 다양한 방식으로 요청을 처리하거나 조작할 수 있게 해준다.
  • 요청의 경로(pathname)가 /profile이면 즉시 메인 페이지(/)로 리다이렉트한다.
  • 로그인 상태 확인은 getSession()을 통해 가능하며, 로그로 세션 데이터를 확인할 수 있다.

Fetch API의 Response 객체란?

미들웨어에서 사용되는 NextResponse는 브라우저의 Fetch API의 Response 인터페이스를 기반으로 한다.

  • Response 객체는 요청(Request)에 대한 응답을 나타낸다.
  • 주로 상태 코드, 헤더, 본문 데이터 등을 포함하여 요청 처리 결과를 반환한다.

예시로, Next.js의 NextResponse를 통해 리다이렉션, JSON 반환, 헤더 설정 등의 작업이 가능하다.

📌 Fetch API Response 공식 문서 (MDN)


자주 사용하는 미들웨어 예제

인증을 위한 미들웨어 예제

아래는 로그인한 사용자만 특정 페이지(/dashboard)에 접근할 수 있도록 설정한 미들웨어이다.

import { NextRequest, NextResponse } from "next/server";
import { getSession } from "@/lib/session";

export async function middleware(request: NextRequest) {
  const session = await getSession();

  if (!session?.userId && request.nextUrl.pathname.startsWith("/dashboard")) {
    // 로그인하지 않은 사용자가 dashboard 접근 시 로그인 페이지로 이동
    return NextResponse.redirect(new URL("/login", request.url));
  }
}

이렇게 하면 사용자의 세션 유무에 따라 접근 가능한 페이지를 효과적으로 제어할 수 있다.


주의사항

  • 미들웨어는 모든 요청에 대해 실행되므로 성능에 주의해야 한다. 필터링 조건을 명확히 하여 꼭 필요한 경우에만 동작하도록 한다.
  • 미들웨어는 middleware.ts 또는 middleware.js프로젝트 루트에 작성하며, 특정 경로에서만 실행되도록 설정하려면 matcher를 활용할 수 있다.

예:

// 특정 경로에서만 미들웨어 실행하기
export const config = {
  matcher: ['/profile', '/dashboard/:path*'],
};

matcher란 무엇인가?

matcher는 미들웨어가 실행될 경로를 명시적으로 정의할 수 있게 해주는 Next.js의 설정 옵션이다. 이를 통해 미들웨어가 모든 요청에서 실행되지 않고, 지정된 경로의 요청에 대해서만 실행되도록 제한할 수 있다.

기본 문법

matcher는 배열 형태로 여러 개의 경로를 지정할 수 있다.

// middleware.ts
export const config = {
  matcher: ["/profile", "/about/:path*", "/dashboard/:path*"],
};
  • /profile: 정확히 /profile 경로에 대해서만 미들웨어 실행
  • /about/:path*: /about 경로 및 하위 경로(/about/team, /about/history 등)에 대해 미들웨어 실행
  • /dashboard/:path*: /dashboard 경로와 모든 하위 경로에서 미들웨어 실행

📌 matcher 공식 문서 - Next.js


matcher에서 정규 표현식(RegEx) 활용하기

matcher는 단순 경로 지정뿐 아니라 복잡한 정규 표현식도 지원하여 보다 정교한 조건을 설정할 수 있다.

정규 표현식 활용 예시

아래 예시는 정규 표현식을 사용하여 특정 조건을 제외한 모든 경로에서 미들웨어가 실행되도록 설정하는 방법이다.

export const config = {
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
};

정규 표현식 설명:

  • (?!...): 부정 예측(negative lookahead)을 뜻하는 정규 표현식으로, 괄호 안의 조건과 일치하지 않는 문자열에 매칭된다.
  • 위 예시는 다음 조건을 제외한 모든 경로에서 미들웨어가 실행된다:
    • /api/...로 시작하는 API 요청
    • /_next/static/..., /_next/image/... 등 Next.js 내부의 정적 자원 요청
    • /favicon.ico 요청

이렇게 하면 미들웨어가 정적 자원 요청이나 API 요청 같은 자주 실행되며 중요하지 않은 요청에 대해 실행되지 않으므로 성능을 최적화할 수 있다.


matcher를 활용한 미들웨어 예제

다음 예제는 사용자의 인증 상태를 검사하는 미들웨어를 특정 보호된 경로에서만 실행하도록 설정한 예제이다.

미들웨어 코드 (middleware.ts)

import { NextRequest, NextResponse } from "next/server";
import { getSession } from "@/lib/session";

export async function middleware(request: NextRequest) {
  const session = await getSession();

  // 사용자가 인증되지 않은 경우 로그인 페이지로 이동
  if (!session?.userId) {
    return NextResponse.redirect(new URL("/login", request.url));
  }
}

// 보호된 경로에만 미들웨어 적용 (matcher 설정)
export const config = {
  matcher: ["/dashboard/:path*", "/profile", "/settings/:path*"],
};
  • 사용자가 인증되지 않은 상태에서 /dashboard, /profile, /settings 등 보호된 페이지 접근 시 자동으로 로그인 페이지로 이동한다.
  • 보호되지 않은 경로에는 미들웨어가 실행되지 않아 성능이 향상된다.

0개의 댓글