제발, 401 오류에서 로그인으로 리다이렉트하는 것을 중지해 주세요 🛑

발행: (2026년 1월 16일 오전 06:57 GMT+9)
5 min read
원문: Dev.to

Source: Dev.to

“Lazy” 패턴

왜 이런 일이 발생할까요? 보통은 JWT(액세스 토큰)가 만료되고, 백엔드가 401 Unauthorized를 반환했으며, 프론트엔드 코드가 튜토리얼대로 정확히 수행했기 때문입니다:

// 이렇게 하면 안 됩니다
axios.interceptors.response.use(null, error => {
  if (error.response.status === 401) {
    window.location.href = '/login'; // 데이터가 사라짐 💀
  }
  return Promise.reject(error);
});

개발자들은 종종 “하지만 보안 요구사항이에요! 세션이 사라졌어요!” 라고 주장합니다.
맞아요, 세션은 사라졌지만 현재 페이지 상태를 모두 죽여야 한다는 뜻은 아닙니다.

더 나은 방법 (복원력)

사용자가 대시보드만 보고 있다면 리다이렉트가 괜찮을 수 있습니다. 하지만 입력 중인 폼, 댓글, 설정 등이 저장되지 않은 상태라면 리다이렉트는 버그가 됩니다.

견고한 앱은 다음 흐름을 처리합니다:

  1. Intercept – 401 오류를 잡아냅니다.
  2. Queue – 실패한 요청을 일시 중지하고 페이지를 새로 고치지 않습니다.
  3. Refresh – 백그라운드에서(리프레시 토큰을 사용) 새 토큰을 얻거나, 비밀번호를 다시 입력하라는 모달을 표시합니다.
  4. Retry – 인증이 완료되면 새 토큰으로 원래 요청을 재시도합니다.

사용자는 전혀 눈치채지 못하고, 폼은 정상적으로 저장됩니다.

어떻게 테스트하나요? (어려운 부분)

“무음 리프레시(silent refresh)”를 구현하는 것은 까다롭고, 테스트하기도 번거롭습니다. 액세스 토큰은 보통 1시간 동안 유효하므로 QA에게 “60분 기다렸다가 저장 버튼을 클릭하라”고 할 수 없습니다.

버튼을 클릭했을 때 정확히 401 오류를 발생시킬 방법이 필요합니다. 토큰이 아직 유효하더라도 말이죠.

“Chaos” 접근법

토큰이 자연스럽게 만료되기를 기다리는 대신, 비행 중에 토큰을 삭제합니다.

Playwright를 사용하면 나가는 요청을 가로채 Authorization 헤더를 제거할 수 있습니다. 이렇게 하면 백엔드가 요청을 거부하고, 앱의 복구 로직이 즉시 실행됩니다.

def test_chaos_silent_logout(page):
    # 1. 로그인하고 폼으로 이동
    page.goto("/login")
    # ... 로그인 로직 수행 ...
    page.goto("/settings/profile")

    # 2. 데이터 입력
    page.fill("#bio", "Important text I don't want to lose.")

    # 3. CHAOS: 'save' 요청 가로채기
    def kill_token(route):
        headers = route.request.headers
        # 토큰을 수동으로 삭제해 만료 상황을 시뮬레이션
        if "authorization" in headers:
            del headers["authorization"]
        # 헤더가 없는 “벌거벗은” 요청을 보냄; 백엔드가 401 반환
        route.continue_(headers=headers)

    # 인터셉터 연결
    page.route("**/api/profile/save", kill_token)

    # 4. 저장 클릭
    page.click("#save-btn")

    # 5. 앱이 복구됐는지 검증
    expect(page.locator("#bio")).to_have_value("Important text I don't want to lose.")
    expect(page.locator(".success-message")).to_be_visible()

요약

네트워크 장애와 토큰 만료는 피할 수 없는 현실입니다. 앱은 사용자를 벌주지 않고 이를 처리해야 합니다. 401 Unauthorized를 치명적인 오류가 아니라 복구 가능한 오류로 다루세요.

PS: Playwright 스크립트를 실행할 수 없는 실제 모바일 디바이스에서 테스트해야 한다면, 네트워크 수준에서 헤더를 제거하는 Chaos Proxy를 사용할 수 있습니다.

Back to Blog

관련 글

더 보기 »

Axios

!Axios용 표지 이미지 https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com...