Next.js 미들웨어로 인증 처리 후 리다이렉션 시 발생하는 정적 파일 로드 오류

ClydeHan·2025년 1월 17일
10
post-thumbnail

1. 문제 발생

1.1 문제 발생 환경

Next.js 미들웨어를 통해 로그인 페이지에 접근 시 토큰이 유효하다면 대시보드로 리다이렉트 시키고, 토큰이 만료됐다면 그대로 로그인 페이지로 접속되게 하는 로직을 구현하려고 했다.

export async function middleware(request: NextRequest) {
	const AUTH_ROUTES: string[] = ['/login']
  const pathname = request.nextUrl.pathname
  
  if (AUTH_ROUTES.includes(pathname)) {
	  // 토큰 검증 및 리다이렉트 로직
  }
}
  • pathname에 현재 경로를 저장한 후 해당 경로가 AUTH_ROUTES배열에서 지정한 경로에 해당되면 토큰 검증 및 리다이렉션 로직을 처리하도록 구현했다.

1.2 발생한 문제

페이지가 정상적으로 렌더링되지 않는다.

  • CSS가 벗겨져 레이아웃이 깨진다.
  • JavaScript 기능이 동작하지 않는다.

브라우저 콘솔 에러(SyntaxError: Unexpected token '<')가 발생한다.

webpack.js?v=1737017745486:1 Uncaught SyntaxError: Unexpected token '<' (at webpack.js?v=1737017745486:1:1)
page.js:1 Uncaught SyntaxError: Unexpected token '<' (at page.js:1:1)
layout.js:1 Uncaught SyntaxError: Unexpected token '<' (at layout.js:1:1)

2. 문제 원인

2.1 CSS 깨짐, 비정상적 렌더링의 원인

Next.js 미들웨어의 작동 방식

원인은 Next.js 미들웨어의 작동 방식에 있다.

지정한 페이지(AUTH_ROUTES)에 /login 페이지가 있었고, 이 페이지에 접근했을 때,pathname/login뿐만 아니라 여러 정적 파일 경로들이 넘어오고 있었다.

<console.log(pathname)> 결과

/_next/static/css/app/layout.css
/_next/static/chunks/webpack.js
/_next/static/chunks/main-app.js
/_next/static/chunks/app-pages-internals.js
/_next/static/chunks/app/(auth)/login/page.js
/_next/static/chunks/app/(auth)/login/layout.js
/login

여기서 중요한 사실은 미들웨어는 프로젝트의 모든 경로(/_next/static/..., /favicon.ico, /login 등)에 대해 실행된다는 것이다. 따라서, 명시적으로 제외하지 않으면 정적 파일 요청도 동일한 미들웨어 로직이 적용된다.

관련 내용: Routing: Middleware

AUTH_ROUTES 배열은 /login 경로를 허용하는데, 정적 파일 요청은 AUTH_ROUTES에 포함되지 않으므로 아래 코드의 로직에 의하여 기본적으로 정적 파일 요청들이 "허용되지 않는 것처럼" 동작하게 된다.

  if (AUTH_ROUTES.includes(pathname)) {
	  // 토큰 검증 및 리다이렉트 로직
  }

결과적으로, /login에 필요한 CSSJS 등의 정적 리소스 요청이 차단되어 페이지가 제대로 렌더링되지 않는다.


2.2 SyntaxError: Unexpected token 에러의 원인

그렇다면 브라우저의 개발자 도구 Console에 나타난 SyntaxError: Unexpected token 에러는 왜 발생한 걸까?

SyntaxError: Unexpected token

이 에러는 브라우저가 자바스크립트를 로드하려고 했는데, 예상치 못한 데이터(오타 등)를 받았을 때 발생한다. 현재 상황에서는 브라우저가 정적 리소스 파일(예: .js.css)을 요청했지만, 미들웨어가 제대로 처리하지 못해 HTML 페이지를 반환한 경우에 발생한다.


에러 발생 경로

  1. 브라우저는 /login 페이지를 렌더링하기 위해 필요한 CSS와 JavaScript를 요청했다.
    • 예: /_next/static/css/app/layout.css와 같은 파일들.
  2. 하지만, 미들웨어가 모든 요청에 실행되면서 정적 리소스 요청(/_next/static/...)도 AUTH_ROUTES 조건을 통과하려고 했다.
  3. AUTH_ROUTES에 정적 리소스 경로가 포함되지 않으므로, 미들웨어는 /login과 같은 동적 페이지 요청처럼 이를 처리하려 했다.
  4. 그 결과, 브라우저가 정적 파일(CSS, JavaScript 등)을 받지 못하고, 대신 HTML 응답(로그인 페이지 등)만을 받게 되었다.
  5. 브라우저는 이 HTML 응답을 JavaScript로 실행하려다 < 문자(HTML의 시작)를 만났고, "예상치 못한 토큰 '<'"이라는 에러를 던졌다.

결론적으로, 브라우저는 정적 리소스를 요청했는데, 미들웨어 때문에 JavaScript 파일 대신 HTML 파일을 받았다. 하지만 자바스크립트가 아니기 때문에 에러가 발생한 것이다.


3. 문제 해결

문제를 해결하는 방법은 정적 리소스 요청을 미들웨어 처리에서 제외하는 것이다.

파일 요청 감지 (pathname.match)

정적 파일 요청은 일반적으로 확장자를 포함하므로, 파일 요청인지 정규식으로 확인할 수 있다.

// 경로에 확장자가 있으면 `true` 없으면 `null`
const isFileRequest = pathname.match(/\.\w+$/);

// 경로에 확장자가 있다면 미들웨어 로직 스킵
if (isFileRequest) {
  return NextResponse.next();
}
  • 정규식 \.\w+$.으로 시작하는 파일 확장자를 포함한 요청을 감지한다.
    • 예: /videos/sample.mp4, /_next/static/css/app.css, /images/logo.png
  • isFileRequesttrue(정적 파일 요청)일 때
    • 정적 파일 요청임을 의미하므로, 미들웨어를 더 이상 실행하지 않고 Next.js의 기본 정적 파일 처리 시스템으로 전달한다.
    • 예: /static/js/main.js, /images/logo.png 같은 정적 파일 요청이 정상적으로 렌더링될 수 있도록 보장한다.
    • 즉, 정적 파일이 미들웨어에서 차단되지 않으므로, 브라우저는 정상적으로 CSS, JS, 이미지 등을 로드할 수 있다.
  • isFileRequestnull(정적 파일 요청이 아님)일 때
    • 정적 파일 요청이 아니라 동적 페이지 요청(예: /login, /dashboard)이므로 미들웨어의 나머지 로직(토큰 검증 및 리다이렉션 로직)을 실행한다.

4. 최종 코드

export async function middleware(request: NextRequest) {
	const AUTH_ROUTES: string[] = ['/login']
  const isFileRequest = request.nextUrl.pathname.match(/\.(.*)$/)
  const pathname = request.nextUrl.pathname
  
  if (isFileRequest) {
	  return NextResponse.next()
}
  
  if (AUTH_ROUTES.includes(pathname)) {
	  // 토큰 검증 및 리다이렉트 로직
  }
}

5. 참고문헌

4개의 댓글

comment-user-thumbnail
2025년 1월 23일

middleware의 matcher속성을 사용하지 않는 이유가 있으실까요??

export const config = {
matcher: ['/login']
}

1개의 답글

관련 채용 정보