본문으로 건너뛰기
개발 머꼬
개발 노트Nuxt.js
hohyeon.dev22

미들웨어에서 navigateTo를 불렀는데 원래 페이지 코드가 실행된 이유

  • #Common Pitfall
  • #Engineering Note
  • #Nuxt.js

문제 발생

미들웨어에서 비로그인 사용자를 로그인 페이지로 보내려 했는데, 리다이렉트가 되긴 하면서도 원래 페이지의 코드가 그대로 실행됐습니다.

export default defineNuxtRouteMiddleware((to) => {
  const user = useUser();
  if (!user.value) {
    navigateTo("/sign-in");   // ❌ 반환하지 않음
  }
});

보호하려던 페이지의 데이터 요청이 그대로 나갔고, 콘솔에는 401이 찍혔습니다.

원인 분석

navigateTo는 호출만 하면 되는 명령형 함수가 아닙니다. 공식 문서가 명시합니다 — navigateTo의 결과에는 항상 awaitreturn을 쓰십시오.

미들웨어에서는 특히 강합니다. 문서는 미들웨어 실행 흐름이 올바르게 동작하려면 그 결과를 반환해야 한다고 적고, 반환하지 않은 예제를 "기대대로 동작하지 않으며 예기치 않은 동작으로 이어질 수 있다"고 표시해 둡니다. 미들웨어는 반환값으로 "이 내비게이션을 다른 곳으로 돌린다"고 라우터에 알리는 구조이기 때문입니다.

<script setup>에서도 비슷한 함정이 있습니다. 문서의 설명대로 navigateTo 호출이 나머지 <script setup> 코드의 실행을 멈추지는 않습니다(실험적 기능 navigateToEarlyReturn을 켜지 않는 한).

해결 방안

  1. 미들웨어에서는 반환합니다.
export default defineNuxtRouteMiddleware((to) => {
  const user = useUser();
  if (!user.value) {
    return navigateTo("/sign-in");
  }
});
  1. setup에서는 뒤 코드가 이어진다는 걸 전제로 씁니다. 조기 반환이 필요하면 직접 끊습니다.
<script setup>
if (!user.value) {
  await navigateTo("/sign-in");
} else {
  const { data } = await useFetch("/api/me");
}
</script>
  1. 외부 URL은 external: true가 필요합니다. 이게 없으면 외부 URL은 오류가 납니다 — 실수로 외부로 튀는 리다이렉트를 막는 안전장치입니다. external: true를 주면 내부 URL도 전체 페이지 새로고침으로 이동합니다.
return navigateTo("https://docs.example.com", { external: true });
  1. 되돌아오면 안 되는 이동은 replace입니다. 기본은 라우터 스택에 쌓지만, 로그인 후 리다이렉트처럼 뒤로 가기로 돌아오면 곤란한 경우에는 현재 항목을 대체합니다.
return navigateTo("/dashboard", { replace: true });
  1. 영구 이동이면 상태 코드를 바꿉니다. 서버 사이드 리다이렉트의 기본값은 302 Found입니다. URL 구조를 바꿔서 검색엔진에 알려야 한다면 301을 명시합니다.
return navigateTo("/notes", { redirectCode: 301 });
  1. 사용자 입력을 그대로 넘기지 않습니다. ?returnTo=처럼 밖에서 온 경로를 검증 없이 navigateTo에 주면 오픈 리다이렉트가 됩니다. 허용 목록을 거친 값만 넘깁니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.