- 미들웨어를 사용하면 요청이 완료되기 전에 코드를 실행할 수 있습니다. 그런 다음 들어오는 요청에 따라 요청 또는 응답 헤더를 다시 작성, 리디렉션, 수정하거나 직접 응답하여 응답을 수정할 수 있습니다
- 미들웨어는 캐시된 콘텐츠와 경로가 일치하기 전에 실행됩니다. 자세한 내용은 일치하는 경로를 참조하세요.
Convention
- 미들웨어를 정의하려면 프로젝트 루트에 있는 middleware.ts(또는 .js) 파일을 사용하세요.
- 예를 들어 페이지나 앱과 동일한 수준이거나 해당하는 경우 src 내부입니다.
Example
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
return NextResponse.redirect(new URL('/home', request.url))
}
export const config = {
matcher: '/about/:path*',
}
Matching Paths (일치하는 경로)
- 프로젝트의 모든 경로에 대해 미들웨어가 호출됩니다. 실행 순서는 다음과 같습니다.
- next.config.js 에서 headers
- next.config.js 에서 redirects
- 미들웨어 (rewrites, redirects 등)
- next.config.js에서 beforeFiles(rewrites)
- 파일 시스템 라우터 (public/ , /_next/static/, pages/ ,app/, etc)
- next.config.js에서 afterFiles(rewrites)
- 동적 경로 (
/blog/[slug]
)
- next.config.js에서 fallback (rewrites)
- 미들웨어가 실행될 경로를 정의하는 방법에는 두 가지가 있습니다.
Matcher
- matcher를 사용하면 미들웨어를 필터링하여 특정 경로에서 실행되도록 할 수 있습니다.
export const config = {
matcher: '/about/:path*',
}
- 배열 구문을 사용하여 단일 경로 또는 다중 경로를 일치시킬 수 있습니다.
export const config = {
matcher: ['/about/:path*', '/dashboard/:path*'],
}
- 일치자 구성은 전체 정규식을 허용하므로 부정 예측 또는 문자 일치와 같은 일치가 지원됩니다.
- 특정 경로를 제외한 모든 경로와 일치하는 부정 예측의 예는 여기에서 볼 수 있습니다.
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|favicon.ico).*)',
],
}
알아두면 좋은 점
- 빌드 시 정적으로 분석할 수 있도록 일치자 값은 상수여야 합니다. 변수와 같은 동적 값은 무시됩니다.
구성된 Matchers
/
로 시작해야합니다.
- 명명된 매개변수를 포함할 수 있습니다.
/about/:path
는 /about/a
및 /about/b
와 일치하지만 /about/a/c
와 일치하지 않습니다.
- 명명된 매개변수에 수정자를 가질 수 있습니다(:로 시작):
/about/:path*
는 *가 0 이상이므로 /about/a/b/c
와 일치합니다. ? 0 또는 1이고 + 1 이상입니다.
- 괄호로 묶인 정규식을 사용할 수 있습니다.
/about/(.*)
는 /about/:path*
와 동일합니다.
- 이전 버전과의 호환성을 위해 Next.js는 항상
/public
을 /public/index
로 간주합니다. 따라서 /public/:path
의 일치자가 일치합니다.
Conditional Statements (조건문)
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로 리디렉션
- 주어진 URL을 렌더링하여 응답을 다시 작성합니다.
- API 경로, getServerSideProps에 대한 요청 헤더 설정 및 대상 재작성
- response 쿠키 설정
- response 헤더 설정
- 미들웨어에서 응답을 생성하려면 다음을 수행할 수 있습니다.
- response를 생성하는 경로(페이지 또는 Route Handler)에 다시 작성
- NextResponse를 직접 반환합니다. 응답 생성을 참조하세요.
Cookies 사용
- 쿠키는 일반 헤더입니다. 요청 시 쿠키 헤더에 저장됩니다. 응답에서는 Set-Cookie 헤더에 있습니다.
- Next.js는 NextRequest 및 NextResponse의 쿠키 확장을 통해 이러한 쿠키에 액세스하고 조작하는 편리한 방법을 제공합니다.
- 들어오는 요청의 경우 쿠키에는 쿠키 가져오기, getAll, 설정 및 삭제 메서드가 함께 제공됩니다. hash를 사용하여 쿠키의 존재를 확인하거나 Clear를 사용하여 모든 쿠키를 제거할 수 있습니다.
- 나가는 응답의 경우 쿠키에는 get, getAll, set 및 delete 메서드가 있습니다.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
let cookie = request.cookies.get('nextjs')
console.log(cookie)
const allCookies = request.cookies.getAll()
console.log(allCookies)
request.cookies.has('nextjs')
request.cookies.delete('nextjs')
request.cookies.has('nextjs')
const response = NextResponse.next()
response.cookies.set('vercel', 'fast')
response.cookies.set({
name: 'vercel',
value: 'fast',
path: '/',
})
cookie = response.cookies.get('vercel')
console.log(cookie)
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) {
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-hello-from-middleware1', 'hello')
const response = NextResponse.next({
request: {
headers: requestHeaders,
},
})
response.headers.set('x-hello-from-middleware2', 'hello')
return response
}
- 백엔드 웹 서버 구성에 따라 431 요청 헤더 필드가 너무 큼 오류가 발생할 수 있으므로 큰 헤더를 설정하지 마십시오.
Response 생성
- Response 또는 NextResponse 인스턴스를 반환하여 미들웨어에서 직접 응답할 수 있습니다. (Next.js v13.1.0부터 사용 가능)
import { NextRequest, NextResponse } from 'next/server'
import { isAuthenticated } from '@lib/auth'
export const config = {
matcher: '/api/:function*',
}
export function middleware(request: NextRequest) {
if (!isAuthenticated(request)) {
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 기본 리디렉션을 비활성화할 수 있으므로 미들웨어 내에서 사용자 지정 처리가 가능해 일부 경로에 대해서는 후행 슬래시를 유지할 수 있지만 다른 경로에서는 유지 관리가 불가능하므로 증분 마이그레이션이 더 쉬워집니다.
module.exports = {
skipTrailingSlashRedirect: true,
}
const legacyPrefixes = ['/docs', '/blog']
export default async function middleware(req) {
const { pathname } = req.nextUrl
if (legacyPrefixes.some((prefix) => pathname.startsWith(prefix))) {
return NextResponse.next()
}
if (
!pathname.endsWith('/') &&
!pathname.match(/((?!\.well-known(?:\/.*)?)(?:[^/]+\/)*[^/]+\.\w+)/)
) {
req.nextUrl.pathname += '/'
return NextResponse.redirect(req.nextUrl)
}
}
- SkipMiddlewareUrlNormalize를 사용하면 Next.js가 수행하는 URL 정규화를 비활성화하여 직접 방문과 클라이언트 전환을 동일하게 처리할 수 있습니다. 잠금 해제되는 원래 URL을 사용하여 완전한 제어가 필요한 몇 가지 고급 사례가 있습니다.
module.exports = {
skipMiddlewareUrlNormalize: true,
}
export default async function middleware(req) {
const { pathname } = req.nextUrl
console.log(pathname)
}
Reference