Next.js beta문서가 공식문서랑 병합 되었다.
미들웨어
미들웨어를 사용하면 요청이 완료되기 전에 코드를 실행할 수 있습니다. 그런 다음 들어오는 요청에 따라 request 또는 response header를 재작성, 리디렉션, 수정하거나 직접 응답하여 response를 수정할 수 있습니다.
알아두면 좋은 사항
- 미들웨어는 캐시된 콘텐츠보다 먼저 실행되므로 정적 파일과 페이지를 개인화할 수 있습니다. 미들웨어의 일반적인 예로는 인증, A/B 테스트, 로컬라이즈된 페이지, 봇 보호 등이 있습니다.
- 미들웨어는 app 라우터 또는 page 라우터보다 먼저 실행되므로 미들웨어 동작은 동일합니다.
- 12.2 이전 버전의 미들웨어를 사용 중인 경우 업그레이드 가이드를 참조하세요.
미들웨어 사용하기
미들웨어 사용을 시작하려면 아래 단계를 따르세요:
Next.js 업데이트
최신 버전의 Next.js를 설치합니다:
npm install next@latest
미들웨어 파일 생성
프로젝트의 루트 디렉터리(app 또는 page 디렉터리와 같은 수준)에 middleware.ts(또는 .js) 파일을 만듭니다.
참고: src 디렉터리를 사용하는 경우 미들웨어 파일을 그 안에 넣으세요.
미들웨어 함수 내보내기
middleware.ts 파일에서 미들웨어 함수를 내보냅니다:
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
// 이 함수는 내부에 `await`을 사용하는 경우 `async`로 표시할 수 있습니다.
export function middleware(request: NextRequest) {
return NextResponse.redirect(new URL('/about-2', request.url));
}
// 자세한 내용은 아래의 'Matching Paths(경로일치)'를 참조하세요.
export const config = {
matcher: '/about/:path*',
};
경로 일치
프로젝트의 모든 경로에 대해 미들웨어가 호출됩니다. 다음은 실행 순서입니다:
- next.config.js의 headers
- next.config.js의 redirects
- 미들웨어(rewrites, redirects 등)
- next.config.js의 beforeFiles(rewrites)
- 파일시스템 경로(public/, _next/static/, 페이지 등)
- next.config.js의 afterFiles(rewrites)
- 동적 경로(/blog/[slug])
- next.config.js의 fallback(rewrites)
미들웨어가 실행될 경로를 정의하는 방법에는 두 가지가 있습니다:
- 사용자 정의 matcher 구성
- 조건문
Matcher
matcher를 사용하면 특정 경로에서 실행할 미들웨어를 필터링할 수 있습니다.
export const config = {
matcher: '/about/:path*',
};
배열 구문을 사용하여 단일 경로 또는 여러 경로를 일치시킬 수 있습니다:
export const config = {
matcher: ['/about/:path*', '/dashboard/:path*'],
};
matcher 구성은 전체 정규식을 허용하므로 네거티브 룩헤드(ex: X(?!Y) X 다음에 Y 가 오지 않는 경우) 또는 문자 일치와 같은 매칭이 지원됩니다. 특정 경로를 제외한 모든 경로를 일치시키는 네거티브 룩헤드의 예는 여기에서 확인할 수 있습니다:
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
*/
'/((?!api|_next/static|_next/image|favicon.ico).*)',
],
};
참고: matcher 값은 빌드 시 정적으로 분석할 수 있도록 상수여야 합니다. 변수와 같은 동적 값은 무시됩니다.
구성된 matcher:
- 반드시 /로 시작해야 합니다.
- 명명된 매개변수를 포함할 수 있습니다: /about/:path는 /about/a 및 /about/b와 일치하지만 /about/a/c와는 일치하지 않습니다.
- 명명된 매개변수에 수정자를 포함할 수 있습니다(:로 시작):
/about/:path* matches /about/a/b/c . 왜냐면 * 은 0 또는 이상 이고, ? 는 0 또는 1 그리고 + 는 1 또는 이상입니다. (뭔소리야) - 괄호로 묶인 정규식을 사용할 수 있습니다: /about/(.*)은 /about/:path*와 동일합니다.
- 경로 정규식 문서에서 자세한 내용을 읽어보세요.
참고: 이전 버전과의 호환성을 위해 Next.js는 항상 /public을 /public/index로 간주합니다. 따라서 /public/:path의 matcher가 일치합니다.
조건문
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/about')) {
return NextResponse.rewrite(new URL('/about-2', request.url));
}
if (request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.rewrite(new URL('/dashboard/user', request.url));
}
}
NextResponse
NextResponse API를 사용하면 다음을 수행할 수 있습니다:
- 들어오는 요청을 다른 URL로 redirect합니다.
- 지정된 URL을 표시하여 응답을 rewrite합니다.
- API 경로, getServerSideProps, rewrite 대상에 대한 요청 헤더 설정
- 응답 쿠키 설정
- 응답 헤더 설정
미들웨어에서 응답을 생성하려면 다음을 수행할 수 있습니다:
- 응답을 생성하는 경로(page 또는 엣지 API 경로)로 rewrite합니다.
- NextResponse를 직접 반환합니다. 응답 생성하기를 참조하세요.
쿠키 사용
쿠키는 일반 헤더입니다. 요청 시에는 쿠키 헤더에 저장됩니다. 응답 시에는 Set-Cookie 헤더에 저장됩니다. Next.js는 NextRequest 및 NextResponse의 쿠키 확장을 통해 이러한 쿠키에 액세스하고 조작할 수 있는 편리한 방법을 제공합니다.
- 들어오는 요청의 경우 쿠키에는 다음과 같은 메서드가 제공됩니다: get, getAll, set 및 delete 쿠키. has를 사용하여 쿠키의 존재 여부를 확인하거나 clear를 사용하여 모든 쿠키를 제거할 수 있습니다.
- 발신 응답의 경우 쿠키에는 get, getAll, set, delete 메서드가 있습니다.
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Assume a "Cookie:nextjs=fast" header to be present on the incoming request
// Getting cookies from the request using the `RequestCookies` API
let cookie = request.cookies.get('nextjs')?.value;
console.log(cookie); // => 'fast'
const allCookies = request.cookies.getAll();
console.log(allCookies); // => [{ name: 'nextjs', value: 'fast' }]
request.cookies.has('nextjs'); // => true
request.cookies.delete('nextjs');
request.cookies.has('nextjs'); // => false
// Setting cookies on the response using the `ResponseCookies` API
const response = NextResponse.next();
response.cookies.set('vercel', 'fast');
response.cookies.set({
name: 'vercel',
value: 'fast',
path: '/test',
});
cookie = response.cookies.get('vercel');
console.log(cookie); // => { name: 'vercel', value: 'fast', Path: '/test' }
// The outgoing response will have a `Set-Cookie:vercel=fast;path=/test` header.
return response;
}
헤더 설정
NextResponse API를 사용하여 요청 및 응답 헤더를 설정할 수 있습니다(요청 헤더 설정은 Next.js v13.0.0부터 가능).
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Clone the request headers and set a new header `x-hello-from-middleware1`
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-hello-from-middleware1', 'hello');
// You can also set request headers in NextResponse.rewrite
const response = NextResponse.next({
request: {
// New request headers
headers: requestHeaders,
},
});
// Set a new response header `x-hello-from-middleware2`
response.headers.set('x-hello-from-middleware2', 'hello');
return response;
}
참고: 백엔드 웹 서버 구성에 따라 431 요청 헤더 필드가 너무 큽니다 오류가 발생할 수 있으므로 큰 헤더를 설정하지 마세요.
응답 생성하기
미들웨어에서 Response 또는 NextResponse 인스턴스를 반환하여 직접 응답할 수 있습니다. (이 기능은 Next.js v13.1.0부터 사용 가능).
import { NextRequest, NextResponse } from 'next/server';
import { isAuthenticated } from '@lib/auth';
// Limit the middleware to paths starting with `/api/`
export const config = {
matcher: '/api/:function*',
};
export function middleware(request: NextRequest) {
// Call our authentication function to check the request
if (!isAuthenticated(request)) {
// Respond with JSON indicating an error message
return new NextResponse(
JSON.stringify({ success: false, message: 'authentication failed' }),
{ status: 401, headers: { 'content-type': 'application/json' } },
);
}
}
고급 미들웨어 플래그
Next.js v13.1에서는 고급 사용 사례를 처리하기 위해 미들웨어에 대한 두 가지 추가 플래그인 skipMiddlewareUrlNormalize 및 skipTrailingSlashRedirect가 도입되었습니다.
skipTrailingSlashRedirect를 사용하면 후행 슬래시를 추가하거나 제거하기 위한 Next.js 기본 리디렉션을 비활성화하여 미들웨어 내부에서 사용자 지정 처리를 할 수 있으므로 일부 경로에는 후행 슬래시를 유지하지만 다른 경로에는 유지하지 않아 증분 마이그레이션을 쉽게 할 수 있습니다.
// next.config.js
module.exports = {
skipTrailingSlashRedirect: true,
};
// middleware.js
const legacyPrefixes = ['/docs', '/blog'];
export default async function middleware(req) {
const { pathname } = req.nextUrl;
if (legacyPrefixes.some((prefix) => pathname.startsWith(prefix))) {
return NextResponse.next();
}
// apply trailing slash handling
if (
!pathname.endsWith('/') &&
!pathname.match(/((?!\.well-known(?:\/.*)?)(?:[^/]+\/)*[^/]+\.\w+)/)
) {
req.nextUrl.pathname += '/';
return NextResponse.redirect(req.nextUrl);
}
}
skipMiddlewareUrlNormalize를 사용하면 Next.js가 수행하는 URL 정규화를 비활성화하여 직접 방문과 클라이언트 전환을 동일하게 처리할 수 있습니다. 원본 URL을 사용하여 완전한 제어가 필요한 고급 사례가 있는데, 이 기능을 사용하면 잠금이 해제됩니다.
// next.config.js
module.exports = {
skipMiddlewareUrlNormalize: true,
};
// middleware.js
export default async function middleware(req) {
const { pathname } = req.nextUrl;
// GET /_next/data/build-id/hello.json
console.log(pathname);
// with the flag this now /_next/data/build-id/hello.json
// 플래그가 없으면 /hello 로 정규화됩니다.
}