junyeokk
Blog
React·2026. 02. 09

Axios 인터셉터

프론트엔드에서 API를 호출할 때, 매번 인증 토큰을 헤더에 넣고 에러 응답을 처리하는 코드를 작성하면 반복이 심해진다. Axios 인터셉터는 모든 HTTP 요청과 응답을 가로채서 공통 로직을 한 곳에서 처리할 수 있게 해준다. "요청이 나가기 전"과 "응답이 돌아온 후"에 자동으로 실행되는 미들웨어라고 생각하면 된다.

인터셉터의 개념

Axios 인터셉터는 두 종류가 있다.

[Request 인터셉터] [Response 인터셉터] 컴포넌트 → 인터셉터 → 서버 서버 → 인터셉터 → 컴포넌트 ↑ 요청 가공 ↑ 응답 가공/에러 처리

Request 인터셉터는 요청이 서버로 나가기 직전에 실행된다. 모든 요청에 인증 헤더를 추가하거나, 요청 로그를 남기는 데 사용한다.

Response 인터셉터는 서버로부터 응답이 돌아온 직후에 실행된다. 특정 에러 코드를 전역적으로 처리하거나, 응답 데이터를 가공하는 데 사용한다.

Request 인터셉터: JWT 자동 첨부

JWT 기반 인증을 사용하면 로그인 후 모든 API 요청에 토큰을 함께 보내야 한다. 매 요청마다 수동으로 헤더를 설정하는 것은 비효율적이고, 하나라도 빠뜨리면 인증 오류가 발생한다. Request 인터셉터를 사용하면 이 작업을 자동화할 수 있다.

typescript
[Request 인터셉터]                    [Response 인터셉터]
컴포넌트 → 인터셉터 → 서버    서버 → 인터셉터 → 컴포넌트
           ↑ 요청 가공                  ↑ 응답 가공/에러 처리

이 인터셉터는 모든 요청이 나가기 전에 실행된다. Zustand 스토어에서 getState()로 현재 토큰을 읽어와 Authorization 헤더에 추가한다. 토큰이 없으면(로그인 전이면) 헤더를 추가하지 않는다.

여기서 useAuthStore.getState()를 사용하는 이유가 중요하다. 인터셉터는 React 컴포넌트가 아니므로 useAuthStore((s) => s.token) 같은 훅 형태를 사용할 수 없다. Zustand의 getState()는 컴포넌트 외부에서 현재 상태를 읽을 수 있는 메서드로, 매 요청마다 호출되어 그 시점의 최신 토큰 값을 가져온다.

인터셉터 함수는 반드시 config 객체를 반환해야 한다. 반환하지 않으면 요청이 전송되지 않는다.

Response 인터셉터: 401 자동 로그아웃

서버가 401(Unauthorized) 응답을 보내는 경우는 토큰이 만료되었거나 유효하지 않다는 의미다. 이때 사용자를 자동으로 로그아웃시키고 로그인 페이지로 보내는 것이 일반적인 패턴이다.

typescript
import { useAuthStore } from '@/features/auth/stores/authStore';

httpClient.instance.interceptors.request.use((config) => {
  const token = useAuthStore.getState().token;
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

Response 인터셉터는 두 개의 함수를 받는다. 첫 번째는 성공 응답(2xx) 핸들러이고, 두 번째는 에러 응답 핸들러다. 성공 응답은 그대로 통과시키고((response) => response), 에러 응답에서 상태 코드를 검사한다.

401 응답이 오면 두 가지 작업을 수행한다. 먼저 clearAuth()로 Zustand 스토어의 인증 정보(토큰, 사용자 정보)를 모두 제거한다. 그다음 window.location.href로 로그인 페이지로 이동시킨다. React Router의 navigate 대신 window.location.href를 사용하는 이유는, 인터셉터가 React 컴포넌트 바깥에 있어서 useNavigate 훅을 사용할 수 없기 때문이다.

마지막에 Promise.reject(error)를 반환하는 것이 중요하다. 이렇게 하면 개별 컴포넌트에서도 에러를 받아서 추가 처리를 할 수 있다. 만약 여기서 에러를 삼켜버리면(reject하지 않으면) 컴포넌트의 onError 핸들러가 실행되지 않는다.

전체 설정 코드

Chiki 프로젝트에서 Axios 인스턴스와 인터셉터를 설정하는 전체 코드를 보면, 깔끔한 구조를 확인할 수 있다.

typescript
httpClient.instance.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      useAuthStore.getState().clearAuth();
      window.location.href = '/login';
    }
    return Promise.reject(error);
  },
);

HttpClient를 생성할 때 baseURL을 환경 변수에서 읽어오고, 두 인터셉터를 순서대로 등록한다. 이 파일에서 내보낸 api 객체를 모든 API 호출에서 사용하면, 토큰 첨부와 401 처리가 자동으로 적용된다.

인터셉터 실행 순서

여러 인터셉터가 등록되었을 때 실행 순서는 다음과 같다.

Request 인터셉터: 등록 순서대로 실행 (첫 번째 → 두 번째 → ...) Response 인터셉터: 등록 역순으로 실행 (마지막 → ... → 첫 번째)

보통 인터셉터를 한두 개만 사용하므로 순서가 중요하지 않지만, 여러 개를 등록할 때는 이 순서를 알아두면 디버깅에 도움이 된다.

요약

Axios 인터셉터는 모든 HTTP 요청과 응답에 공통 로직을 적용하는 미들웨어다. Request 인터셉터에서 Zustand의 getState()로 토큰을 읽어 헤더에 첨부하면 매 요청마다 토큰을 수동으로 넣을 필요가 없다. Response 인터셉터에서 401 응답을 감지해 인증 상태를 초기화하고 로그인 페이지로 리다이렉트하면 토큰 만료를 전역에서 일관되게 처리할 수 있다.