stack-analysis
CHAPTER 16 / 90
읽기 약 2분
FUNCTION
미들웨어 실전: 인증 + 지역화 + A/B 테스트
핵심 개념
middleware.ts·matcher·NextResponse — 인증 게이트·로케일 리다이렉트·실험.
본문
기본 미들웨어
// middleware.ts (루트)
import { NextResponse, NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// 모든 요청 전에 실행
const url = request.nextUrl.clone();
// 1. 헤더 추가
const response = NextResponse.next();
response.headers.set('x-correlation-id', crypto.randomUUID());
return response;
}
export const config = {
matcher: [
// _next, api, 정적 파일 제외
'/((?!api|_next/static|_next/image|favicon.ico).*)',
],
};인증 게이트
import { NextResponse, NextRequest } from 'next/server';
import { jwtVerify } from 'jose';
const JWT_SECRET = new TextEncoder().encode(process.env.JWT_SECRET!);
export async function middleware(request: NextRequest) {
const path = request.nextUrl.pathname;
// 보호 경로
if (path.startsWith('/dashboard') || path.startsWith('/admin')) {
const token = request.cookies.get('auth-token')?.value;
if (!token) {
const url = request.nextUrl.clone();
url.pathname = '/login';
url.searchParams.set('callbackUrl', path);
return NextResponse.redirect(url);
}
try {
const { payload } = await jwtVerify(token, JWT_SECRET);
// 관리자 경로 추가 검증
if (path.startsWith('/admin') && payload.role !== 'admin') {
return NextResponse.redirect(new URL('/403', request.url));
}
// 사용자 정보 헤더로 전달
const response = NextResponse.next();
response.headers.set('x-user-id', payload.sub as string);
response.headers.set('x-user-role', payload.role as string);
return response;
} catch {
return NextResponse.redirect(new URL('/login', request.url));
}
}
return NextResponse.next();
}지역화 (i18n) 리다이렉트
const SUPPORTED_LOCALES = ['ko', 'en', 'ja', 'zh'];
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// 이미 로케일이 있으면 통과
const hasLocale = SUPPORTED_LOCALES.some(
l => pathname === `/${l}` || pathname.startsWith(`/${l}/`)
);
if (hasLocale) return NextResponse.next();
// Accept-Language로 추론
const acceptLang = request.headers.get('accept-language') ?? '';
const detected = SUPPORTED_LOCALES.find(l => acceptLang.includes(l)) ?? 'ko';
// 쿠키에 저장된 선호 언어 우선
const preferred = request.cookies.get('locale')?.value;
const locale = preferred && SUPPORTED_LOCALES.includes(preferred) ? preferred : detected;
const url = request.nextUrl.clone();
url.pathname = `/${locale}${pathname}`;
return NextResponse.redirect(url);
}A/B 테스트
export function middleware(request: NextRequest) {
// 이미 그룹 할당됨
let bucket = request.cookies.get('ab-bucket')?.value;
if (!bucket) {
// 50/50 할당
bucket = Math.random() < 0.5 ? 'A' : 'B';
}
// /home → /home-A 또는 /home-B 리라이트 (URL은 그대로)
const url = request.nextUrl.clone();
if (url.pathname === '/' || url.pathname === '/home') {
url.pathname = `/home-${bucket}`;
}
const response = NextResponse.rewrite(url);
response.cookies.set('ab-bucket', bucket, { maxAge: 60 * 60 * 24 * 30 });
return response;
}다음 챕터
CH.17 "이미지 최적화" — next/image + CDN.
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude
무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6
내 코드의 Next.js 미들웨어 부분을 분석해서 실전 분석 + 개선 우선순위를 알려줘.
ChatGPT
무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro
Next.js 미들웨어 관련 인기 라이브러리/패턴 5개를 비교 분석해서 패턴 추출를 알려줘.
Gemini
무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro
내 프로젝트 전체에서 Next.js 미들웨어 최적화 가능 위치를 보고해줘.
Grok
무료: Grok 4.1 / SuperGrok $30/mo
2026년 한국 프론트엔드 시장의 Next.js 미들웨어 트렌드를 솔직히 알려줘.
⭐ 이것만 기억하세요
미들웨어 실전: 인증 + 지역화 + A/B 테스트는 이 3가지만 확실히 잡으세요
1.미들웨어 = 모든 요청 전에 실행 — 인증/i18n/A/B 표준
2.NextResponse.redirect / rewrite / next() 3가지 응답
3.matcher로 적용 경로 제어 — 정적 파일 제외
공유하기
진행도 16 / 90