: 요청(Request)과 응답(Response) 사이에서 실행되는 중간 처리 로직을 정의
미들웨어 사용 케이스
1. 인증 및 권한 부여: 특정 페이지나 API 라우트에 대한 액세스 권한을 부여하기 전에 사용자 신원을 확인하고 세션 쿠키를 확인할 때 사용할 수 있습니다.
2. 서버 사이드 리디렉션: 특정 조건(예: local, 사용자 조건)에 따라 서버에서 사용자를 리디렉션합니다.
3. 경로 Rewriting: request 속성을 기반으로 API 라우트 또는 페이지에 대한 라우트를 동적으로 재작성하여 A/B 테스트, 기능 출시 또는 레거시 경로를 지원합니다.
4. 봇 탐지: 봇 트래픽을 탐지하고 차단하여 리소스를 보호합니다.
5. 로깅 및 분석
특징
- 모든 request당 이 미들웨어가 실행
(페이지이동, css, js, 이미지, favicon 등..)
- Edge runtime에서 실행됨. (node.js가 아님)
- 미들웨어에서 사용되는 node.js의 경량 버전
- 모든 요청에 middleware가 실행되다보니, 처리에 시간이 걸리는 nodeJS 전용 api(ex. prisma)는 실행할 수 없음
- 호환 api 목록 : https://nextjs.org/docs/app/api-reference/edge
만드는 방법
- app과 같은 레벨에 middleware.ts 파일을 만듦
- middleware 이름을 가진 일반함수 작성 ㅇㅇ
- 비동기이든, 매개변수가 뭐든 상관없음
- request:NextRequest를 매개변수로 가질 수 있음
특정 요청에만 middleware가 실행되도록 하는법
- 방법1. if-else
- 방법2. matcher
1) middleware.ts 파일에 config 라는 이름의 객체 생성,
2) matcher key로 middleware를 거쳐갈 path 작성
export const config = { matcher: ["/", "/user/:path*",] } //정규식을 사용해서 제외할 수도 있음 // 브라우저가 요청하는 url 제외하기 export const config = { matcher: ["/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",] }
- 이걸 하지 않고 리다이렉트 하는 응답을 리턴하면, css도 적용이 안되는 문제 발생~
middleware에서 할 수 있는 작업 예시
1. 응답 조작하기
//json데이터가 담긴 응답 return Response.json({error: "this is not available"}) //url(절대경로여야 함)로 이동하는 응답 return Response.redirect(new URL(”/”,request.url))
2. 사용자에게 주는 실제 응답에 쿠키를 넣기
- NextResponse : 표준 웹 API의
Response
객체를 확장한 형태
import { NextResponse } from 'next/server' ... const response = NextResponse.next() //요청을 그대로 진행. 실제응답을 리턴 response.cookies().set("middleware-cookie") //응답에 쿠키 끼워넣기 return response }
3. 세션 작업
세션이 없으면 인증 관련 페이지만 접근하도록 함
세션이 있으면 인증 관련 페이지를 접근하지 못하도록 함
import { NextRequest, NextResponse } from "next/server"; import getSession from "./libs/session"; const publicPathnames = new Set(["/", "/login", "/create-account", "/sms"]); export async function middleware(request: NextRequest) { const session = await getSession(); const isPublic = publicPathnames.has(request.nextUrl.pathname); if (!session.id && !isPublic) { return NextResponse.redirect(new URL("/", request.url)); } if (session.id && isPublic) { console.log(request.url); return NextResponse.redirect(new URL("/products", request.url)); } } export const config = { matcher: [ "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)", ], };
..그외 헤더 작업 등도 할 수 있음
FYI
- Next.js에는 애플리케이션에서 사용할 수 있는 두 가지 서버 런타임
1. Node.js 런타임(기본값): 생태계의 모든 Node.js API 및 호환 패키지에 액세스
2. Edge 런타임: 제한된 API를 지원하는 Edge 런타임
- new URL(url,baseUrl)는 baseUrl의 path이하를 뺀 링크를 의미