[Next.js] Middleware

파이리·2023년 8월 2일
0

Next.js

목록 보기
13/18
post-thumbnail

미들웨어를 사용하면 요청이 완료되기 전에 코드를 실행할 수 있습니다. 그런 다음 들어오는 요청에 따라 요청 또는 응답 헤더를 재작성, 리디렉션, 수정하거나 직접 응답하며 응답을 수정할 수 있습니다.

미들웨어는 캐시된 콘텐츠와 경로가 일치하기 전에 실행됩니다. 자세한 내용은 경로 매칭을 참조하세요.

Convention

프로젝트의 루트에서 middleware.js 파일을 사용하여 미들웨어를 정의합니다. 예를 들어 page 또는 app과 같은 수준 또는 해당되는 경우 src안에 정의합니다.

Example

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*',
}

Matching Paths

프로젝트의 모든 경로에 대해 미들웨어가 호출됩니다. 실행 순서는 다음과 같습니다.

  1. next.confing.jsheaders
  2. next.confing.jsredirects
  3. 미들웨어
  4. next.confing.jsbeforeFiles
  5. 파일시스템 경로
  6. next.confing.jsafterFiles
  7. 동적 경로
  8. next.confing.jsfallback

미들웨어가 실행될 경로를 정의하는 방법에는 두 가지가 있습니다.

  • 사용자 지정 matcher 구성
  • 조건문

Matcher

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 값은 빌드 시 정적으로 분석할 수 있도록 상수여야 합니다. 변수와 같은 동적 값은 무시됩니다.

  1. 반드시 /로 시작해야 합니다.

  2. 명명된 매개변수를 포함할 수 있습니다. : /about/:pathabout/aabout/b 일치하지만 about/a/c와 일치하지 않습니다.

  3. 명명된 매개변수에 수정자를 포함할 수 있습니다. : about/:path*/about/a/b/c와 일치합니다. 이는 *0과 그 이상, ?01 중 하나, +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

NextResponse API를 사용하면 다음을 수행할 수 있습니다.

  • 들어오는 요청을 다른 URL로 리디렉션합니다.
  • 지정된 URL을 표시하여 응답을 rewirte합니다.
  • 요청 헤더에 API 라우트, getServerSidePropsrewrite 대상에 대한 설정
  • 응답 쿠키 설정
  • 응답 헤더 설정

미들웨어에서 응답을 생성하려면 다음과 같이 할 수 있습니다.

  1. 응답을 생성하는 경로로 재작성합니다.
  2. NextResponse를 직접 반환합니다.

쿠키 사용하기

쿠키는 일반 헤더입니다. 요청 시에는 쿠키 헤더에 저장됩니다. 응답에서는 Set-Cookie 헤더에 저장됩니다. Next.js는 NextRequest의 쿠키 확장을 통해 이러한 쿠키에 엑세스하고 조작할 수 있는 편리한 방법을 제공합니다.

  1. 들어오는 요청의 경우 쿠키에는 다음과 같은 메서드가 제공됩니다. : get, getAll, set, delete, has를 사용하여 쿠키의 존재 여부를 확인하거나 clear를 사용해 모든 쿠키를 제거할 수도 있습니다.

  2. 발신 응답의 경우 쿠키에는 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
}
profile
프론트엔드 개발자

0개의 댓글