
2025.3.31 월요일의 공부기록
이 글에서는 Next.js에서 미들웨어(Middleware) 가 무엇인지, 어떤 상황에서 사용하면 좋은지 구체적인 사례와 함께 살펴본다. 또한 실제 프로젝트에서 미들웨어를 적용하는 실습 코드와 함께 Fetch API의 Response 인터페이스에 대해서도 간단히 알아본다.
미들웨어는 사용자의 요청(request)이 서버에서 최종적으로 처리되기 전에 중간에서 실행되는 코드이다. 즉, Next.js에서 미들웨어는 요청이 라우팅되어 페이지나 API에 도달하기 전에 개입하여 추가 작업을 수행할 수 있다.
특히 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()을 통해 가능하며, 로그로 세션 데이터를 확인할 수 있다.미들웨어에서 사용되는 NextResponse는 브라우저의 Fetch API의 Response 인터페이스를 기반으로 한다.
예시로, 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는 미들웨어가 실행될 경로를 명시적으로 정의할 수 있게 해주는 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는 단순 경로 지정뿐 아니라 복잡한 정규 표현식도 지원하여 보다 정교한 조건을 설정할 수 있다.
아래 예시는 정규 표현식을 사용하여 특정 조건을 제외한 모든 경로에서 미들웨어가 실행되도록 설정하는 방법이다.
export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
};
(?!...): 부정 예측(negative lookahead)을 뜻하는 정규 표현식으로, 괄호 안의 조건과 일치하지 않는 문자열에 매칭된다./api/...로 시작하는 API 요청/_next/static/..., /_next/image/... 등 Next.js 내부의 정적 자원 요청/favicon.ico 요청이렇게 하면 미들웨어가 정적 자원 요청이나 API 요청 같은 자주 실행되며 중요하지 않은 요청에 대해 실행되지 않으므로 성능을 최적화할 수 있다.
다음 예제는 사용자의 인증 상태를 검사하는 미들웨어를 특정 보호된 경로에서만 실행하도록 설정한 예제이다.
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 등 보호된 페이지 접근 시 자동으로 로그인 페이지로 이동한다.