ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Next.js 미들웨어로 온보딩 접근 제어 구현하기
    프론트엔드 2025. 8. 13. 20:00

    프로젝트에 미들웨어 도입하기 

    - 미들웨어??? 🤔 미들웨어란 요청과(requset)와 응답(response) 사이에 동작하며, 일종의 중간다리 역할이다. 

     

    Next.js에서는 middleware.ts 파일을 루트에 두면 페이지·API 요청 시 자동으로 실행된다.

    핵심은 페이지가 렌더링되기 전에 실행된다는 점이다.

     

     

    예시)

    클라이언트 → [미들웨어] → 서버 로직
    서버 로직 → [미들웨어] → 클라이언트

    -> 이처럼 미들웨어는 중간다리 역할을 한다. 

     

    Next.js 미들웨어 실행 순서

    Next.js 미들웨어는 Edge Runtime 위에서 실행된다. 일반 Node.js 환경과 다르다.

    Next.js에서 요청이 들어오면 다음 순서로 처리된다.

    1. 요청 수신
    2. middleware.ts 실행  ← 여기서 가로챔
    3. 통과 시 → 해당 라우트 처리 (SSR, API Route 등)
    4. 응답 반환

    즉 getServerSideProps, page 컴포넌트, route handler 중 어떤 것도 미들웨어보다 먼저 실행되지 않는다. 미들웨어가 NextResponse.next()를 반환해야만 다음 단계로 넘어간다.

     

    미들웨어 사용 

    - middleware.ts 파일을 프로젝트 루트에 두면 끝이다. 별도 설정 없이 요청마다 자동으로 실행된다.

    - 현재는 proxy.ts로 바뀌었다 

    // middleware.ts
    import { NextRequest, NextResponse } from "next/server";
    
    export default function middleware(req: NextRequest) {
      const token = req.cookies.get("token");
    
      if (!token) {
        return NextResponse.redirect(new URL("/login", req.url));
      }
    
      return NextResponse.next();
    }
    
    export const config = {
      matcher: ["/dashboard/:path*", "/mypage/:path*"],
    };

    - matcher로 미들웨어가 실행될 경로를 지정할 수 있다. 설정하지 않으면 이미지·CSS 요청에도 전부 실행되니 꼭 범위를 좁혀야 한다.

     

    프로젝트 적용 — 온보딩 접근 제어

    문제 상황

    • 신규 유저가 온보딩 없이 바로 대시보드로 진입
    • 온보딩 완료 여부를 기억하지 못해 재방문 시 반복 노출
    • 클라이언트 리다이렉트 방식은 페이지가 렌더링된 후 쿠키를 확인하기 때문에 대시보드 화면이 잠깐 노출되는 flash 현상 발생

    해결

    온보딩 마지막 단계에서 쿠키를 설정하고, Middleware에서 이를 확인해 접근을 제어했다.
    클라이언트 리다이렉트 방식과 달리 Middleware는 렌더링 전 서버에서 먼저 확인하기 때문에 flash 현상 없이 접근을 차단할 수 있었다.

    주의사항 + 트러블슈팅

    1. matcher 꼭 설정할 것 설정하지 않으면 이미지·CSS·폰트 요청에도 전부 실행된다.

    export const config = {
      matcher: ["/dashboard/:path*"],
    };

    2. 무한 리다이렉트 실제로 겪은 문제다. /onboarding을 matcher에 포함했더니 온보딩 페이지 자체에도 Middleware가 실행되어 /onboarding → /onboarding → ... 무한 루프가 발생했다. 리다이렉트 목적지는 matcher에서 반드시 제외해야 한다.

    3. 로직은 가볍게 Middleware는 모든 요청마다 실행된다. 무거운 연산을 넣으면 전체 응답 속도에 영향을 준다. 쿠키·토큰 확인 정도만 처리하는 것이 적합하다.

     

    무한루프 🥹
    미들웨어의 정상적 흐름은 아래처럼 진행되어야 한다. 
    유저가 /dashboard 접속
    → Middleware 실행
    → 쿠키 없음
    → /onboarding으로 리다이렉트
    → 끝​

     

    무한 루프 발생 흐름

    matcher에 /onboarding이 포함돼 있으면??
    유저가 /dashboard 접속
    → Middleware 실행 → 쿠키 없음 → /onboarding으로 리다이렉트
    → /onboarding 접속
    → Middleware 또 실행 → 쿠키 없음 → /onboarding으로 리다이렉트
    → /onboarding 접속
    → Middleware 또 실행 → ...
    → 무한 반복 💥​


    해결은 matcher에서 /onboarding 제외하면 끝

    export const config = {
      matcher: [
        "/dashboard/:path*",
        // /onboarding 은 여기 없어야 함
      ],
    };​

     

    한계 및 회고

    쿠키는 브라우저 데이터를 초기화하면 사라지기 때문에 다기기 환경에서는 온보딩이 재노출될 수 있다. 로그인 기반 서비스라면 DB에 완료 여부를 저장하는 방식이 더 적합하다. 이 프로젝트에서는 온보딩 재노출이 허용 가능한 수준이고 구현 복잡도를 낮추기 위해 쿠키로 충분하다고 판단했지만, 다음에 비슷한 기능을 구현한다면 유저 테이블에 onboarding_done 컬럼을 추가하는 방식을 고려할 것 같다.

     

    '프론트엔드' 카테고리의 다른 글

    package.json + package.lock.json  (3) 2025.08.15
    Date.prototype.toISOString()  (0) 2025.08.13
    TanStack Query 적용해보기  (5) 2025.08.12
    클린 아키텍쳐를 프로젝트에 적용해보자  (0) 2025.08.05
    Git Merge 방법  (3) 2025.08.02
Designed by Tistory.