미들웨어 사용
Next.js의 미들웨어 기능은 요청이 완료되기 전에 코드를 실행할 수 있게 해주는 강력한 도구입니다.
이 절에서는 미들웨어의 기본 개념, 사용 사례, 그리고 API 라우트와의 통합에 대해 알아보겠습니다.
미들웨어 기본 개념
미들웨어는 요청이 서버에 도달하기 전에 실행되는 함수입니다.
이를 통해 요청을 수정하거나, 응답을 조작하거나, 리다이렉션을 수행할 수 있습니다.
미들웨어 파일 생성 및 구성
Next.js에서 미들웨어를 사용하려면 프로젝트 루트에 middleware.js
또는 middleware.ts
파일을 생성합니다.
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 요청에 대한 로깅과 기본적인 인증 체크를 수행하는 미들웨어를 구현해보겠습니다.
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).*)',
],
}
이 미들웨어는 다음과 같은 기능을 수행합니다.
- 모든 요청에 대해 메서드, URL, 시간을 로깅합니다.
/api/
로 시작하는 모든 요청에 대해 기본적인 인증 체크를 수행합니다.- 유효한 Bearer 토큰이 없는 API 요청을 거부합니다.
- 인증된 요청에 대해 사용자 ID를 헤더에 추가합니다.
이 실습을 통해 미들웨어를 사용하여 API 요청을 로깅하고 기본적인 인증을 구현하는 방법을 익힐 수 있습니다.
실제 애플리케이션에서는 더 복잡한 인증 로직과 토큰 검증이 필요할 것입니다.
Next.js의 미들웨어는 애플리케이션의 보안, 로깅, 라우팅 제어 등 다양한 용도로 활용될 수 있는 강력한 기능입니다.
API 라우트와 결합하여 사용하면 더욱 유연하고 안전한 백엔드 로직을 구현할 수 있습니다.