미들웨어를 사용하면 요청이 완료되기 전에 코드를 실행할 수 있다. 그런 다음 들어오는 요청에 따라 요청 또는 응답 헤더를 다시 작성, 리디렉션, 수정하거나 직접 응답하여 응답을 수정할 수 있다. 미들웨어는 캐시 된 콘텐츠와 경로가 일치하기 전에 실행된다.
- Convention
프로젝트 루트에 있는 middleware.ts(또는 .js) 파일을 사용하여 미들웨어를 정의한다. 예를 들어 페이지 또는 앱과 동일한 수준 또는 해당하는 경우 src 내부에 있다.
- Example
// middleware.ts
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.redirecct(new URL('/home', request.url));
}
// See 'Matching Paths' bellow th learn more
export const config = {
matcher: '/about/:path*',
};
- Matching Paths
프로젝트의 모든 경로에 대해 미들웨어가 호출된다. 실행 순서는 다음과 같다.
- next.config.js의 헤더
- next.config.js에서 리디렉션
- 미들웨어(재작성, 리디렉션 등)
- next.config.js의 beforeFiles(재작성)
- 파일 시스템 경로(pulic/, _next/static/, pages/, app/ 등)
- next.config.js에서 afterFiles(재작성)
- 동적 경로(/blog/[slug])
- next.config.js에서 폴백(rewrites)
미들웨어가 실행될 경로를 정의하는 두 가지 방법이 있다. 첫 번째는 Custom matcher config이고, 두 번째는 Conditional statements이다.
- Matcher
matcher를 사용하면 특정 경로에서 실행되도록 미들웨어를 필터링할 수 있다.
// middleware.js
export const config = {
matcher: '/about/:path*',
};
배열 구문을 사용하여 단일 경로 또는 다중 경로를 일치시킬 수도 있다.
// middleware.js
export const config = {
matcher: ['/about/:path*', /dashboard/:path*],
};
matcher 구성은 전체 정규식을 허용하므로 부정 예측 또는 문자 일치와 같은 matching이 지원된다. 특정 경로를 제외한 모든 경로와 일치하는 부정적인 미리 보기의 예는 다음에서 볼 수 있다.
// middleware.js
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/c와 일치하지 않음.
- 명명된 매개변수에 수정자를 가질 수 있다. (:)로 시작한다. /about/:path*는 *가 0 이상이므로 /about/a/b/c와 일치한다. ?은 0 또는 1이고 +는 1 이상이다.
- 괄호로 묶인 정규식을 사용할 수 있다. /about/(.*)는 /about/:path*와 동일하다.
- Conditional Statements
// 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('/dashbaord/user', request.url));
}
}
- NextResponse
NextResponse API를 사용하면 다음을 수행할 수 있다.
- 들어오는 요청을 다른 URL로 리디렉션
- 주어진 URL을 표시하여 응답을 다시 작성
- API 경로, getServerSideProps 및 재작성 대상에 대한 요청 헤더 설정
- 응답 쿠키 설정
- 응답 헤더 설정
미들웨어에서 응답을 생성하려면 다음을 수행할 수 있다. 먼저, 응답을 생성하는 경로(페이지 또는 Edge API 경로)에 다시 쓰기가 가능하다. 그리고 NextResponse를 직접 반환할 수 있다.
- Using Cookies
쿠키는 일반 헤더이다. 요청 시 쿠키 헤더에 저장된다. 응답에서 쿠키는 Set-Cookie 헤더에 있다. Next.js는 NextRequest 및 NextResponse의 쿠키 확장을 통해 이러한 쿠키에 액세스 하고 조작하는 편리한 방법을 제공한다.
- 들어오는 요청의 경우 쿠키는 get, getAll, set 및 delete와 같은 메서드와 함께 제공된다. has를 사용하여 쿠키의 존재를 확인하거나 clear를 사용하여 모든 쿠키를 제거할 수 있다.
- 나가는 응답의 경우 쿠키에는 get, getAll, set 및 delete 메서드가 있다.
// middleware.js
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 incomming 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;
}
- Setting Headers
NextResponse API를 사용하여 요청 및 응답 헤더를 설정할 수 있다.(요청 헤더 설정은 Next.js v13.0.0부터 사용 가능)
// middleware.ts
import ( NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(reqeust: NextRequest) {
// Clone the request headers and set a new header 'x-hello-from-middleware1'
const reqeustHeaders = 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;
}
- Producing a Response
Response 또는 NextResponse 인스턴스를 반환하여 미들웨어에서 직접 응답할 수 있다. (Next.js v13.1.0부터 가능)
// middleware.ts
import { NextReqeust, 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 reqeust
if (!isAuthenticated(reqeust)) {
// Response with JSON indicating an error message
return new NextResponse(
JSON.stringify({ success: false, message: 'authentication failed' }),
{ status: 401, headers: { 'content-type': 'application/json' } },
);
}
}
- Advanced Middleware Flags
Next.js v13.1에서는 고급 사용 사례를 처리하기 위해 미들웨어용 skipMiddlewareUrlNormalize 및 skipTrailingSlashRedirect라는 두 개의 추가 슬래시가 도입되었다.
skipTrailingSlashRedirect는 후행 슬래시를 추가하거나 제거하기 위한 Next.js 기본 리디렉션을 비활성화할 수 있다. 미들웨어 내에서 사용자 지정 처리를 허용하여 일부 경로에 대해 후행 슬래시를 유지할 수 있지만 다른 경로는 유지하지 않고 더 쉽게 증분 마이그레이션을 허용할 수 있다.
// next.config.js
module.exports = {
skipTrailingSlashRedirect: true,
};
// middleware.js
const lagacyPrefixes = ['/docs', '/blog'];
export default async function middleware(req) {
const { pathname } = requ.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.redurect(req.nextUrl);
}
}
skipMiddlewareUrlNormalize는 URL 정규화를 비활성화할 수 있다. Next.js는 직접 방문과 클라이언트 전환을 동일하게 처리한다. 이렇게 하면 잠금이 해제되는 원래 URL을 사용하여 전체 제어가 필요한 몇 가지 고급 사례가 있다.
// next.config.js
module.exports = {
skipMiddlewareUrlNormailize: 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
// without the flag this would be normalized to /hello
}
'Next.js' 카테고리의 다른 글
Next.js 11-13 Routing Internationalization (1) | 2023.06.08 |
---|---|
Next.js 11-12 Routing Project Organization File Colocation (0) | 2023.06.02 |
Next.js 11-10 Routing Route Handlers (0) | 2023.05.31 |
Next.js 11-9 Routing Intercepting Routes (0) | 2023.05.30 |
Next.js 11-8 Routing Parallel Routes (0) | 2023.05.26 |