미들웨어를 사용하면 요청이 완료되기 전에 코드를 실행할 수 있습니다. 그런 다음 들어오는 요청에 따라 요청 또는 응답 헤더를 재작성, 리디렉션, 수정하거나 직접 응답하며 응답을 수정할 수 있습니다.
미들웨어는 캐시된 콘텐츠와 경로가 일치하기 전에 실행됩니다. 자세한 내용은 경로 매칭을 참조하세요.
프로젝트의 루트에서 middleware.js
파일을 사용하여 미들웨어를 정의합니다. 예를 들어 page
또는 app
과 같은 수준 또는 해당되는 경우 src
안에 정의합니다.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
return NextResponse.redirect(new URL('/home', request.url))
}
// See "Matching Paths" below to learn more
export const config = {
matcher: '/about/:path*',
}
프로젝트의 모든 경로에 대해 미들웨어가 호출됩니다. 실행 순서는 다음과 같습니다.
next.confing.js
의 headers
next.confing.js
의 redirects
next.confing.js
의 beforeFiles
next.confing.js
의 afterFiles
next.confing.js
의 fallback
미들웨어가 실행될 경로를 정의하는 방법에는 두 가지가 있습니다.
matcher
를 사용하면 특정 경로에서 실행되도록 미들웨어를 필터링할 수 있습니다.
export const config = {
matcher: '/about/:path*',
}
배열 구문을 사용해 단일 경로, 또는 여러 경로를 일치시킬 수 있습니다.
export const config = {
matcher: ['/about/:path*', '/dashboard/:path*'],
}
matcher
설정은 전체 정규식을 허용하므로 네거티브 록헤드 또는 문자 일치와 같은 매칭이 지원됩니다. 특정 경로를 제외한 모든 경로를 일치시키는 네거티트 록헤드의 예는 아래에서 확인할 수 있습니다.
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
값은 빌드 시 정적으로 분석할 수 있도록 상수여야 합니다. 변수와 같은 동적 값은 무시됩니다.
반드시 /
로 시작해야 합니다.
명명된 매개변수를 포함할 수 있습니다. : /about/:path
는 about/a
및 about/b
일치하지만 about/a/c
와 일치하지 않습니다.
명명된 매개변수에 수정자를 포함할 수 있습니다. : about/:path*
는 /about/a/b/c
와 일치합니다. 이는 *
는 0
과 그 이상, ?
는 0
과 1
중 하나, +
은 1
과 그 이상을 의미하기 때문입니다.
괄호로 묶인 정규식을 사용할 수 있습니다. : /about/(.*)
는 /about/:path*
와 같은 의미입니다.
더 자세한 내용은 path-to-regexp을 참조하세요.
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
API를 사용하면 다음을 수행할 수 있습니다.
rewirte
합니다.getServerSideProps
및 rewrite
대상에 대한 설정미들웨어에서 응답을 생성하려면 다음과 같이 할 수 있습니다.
쿠키는 일반 헤더입니다. 요청 시에는 쿠키 헤더에 저장됩니다. 응답에서는 Set-Cookie
헤더에 저장됩니다. Next.js는 NextReques
t의 쿠키 확장을 통해 이러한 쿠키에 엑세스하고 조작할 수 있는 편리한 방법을 제공합니다.
들어오는 요청의 경우 쿠키에는 다음과 같은 메서드가 제공됩니다. : 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')
console.log(cookie) // => { name: 'nextjs', value: 'fast', Path: '/' }
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: '/',
})
cookie = response.cookies.get('vercel')
console.log(cookie) // => { name: 'vercel', value: 'fast', Path: '/' }
// The outgoing response will have a `Set-Cookie:vercel=fast;path=/test` header.
return response
}
NextResponse API
를 사용하여 요청 및 응답 헤더를 설정할 수 있습니다.
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
}
미들웨어에서 Response
또는 NextResponse
인스턴스를 반환하여 직접 응답할 수 있습니다.
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 기본 리디렉션을 비활성화하여 미들웨어 내부에서 사용자 지정 처리를 할 수 있으므로 일부 경로에는 후행 슬래시를 유지하지만 다른 경로에는 유지하지 않아 증분 마이그레이션을 쉽게 할 수 있습니다.
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()
}
// 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을 사용하여 완전한 제어가 필요한 고급 사용 사례가 있는데, 이 기능을 사용하면 잠금이 해제됩니다.
module.exports = {
skipMiddlewareUrlNormalize: true,
}
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
// without the flag this would be normalized to /hello
}