티스토리 뷰

서버에 데이터를 요청할 때 헤더에 액세스 토큰을 포함하는 경우가 많습니다. 이 때 액세스 토큰이 만료되면 서버에서 401 에러를 응답받게 되는데, 사용자 경험을 고려하면 액세스 토큰이 만료되었을 때 리프레시 토큰으로 새로운 액세스 토큰을 발급받고 다시 서버에 요청하는 것이 좋습니다. 이를 구현하기 위해서는 axios에서 제공하는 interceptors를 사용하여 구현할 수 있습니다.

 

1. axios 인스턴스 생성

// api 인스턴스 생성
const api = axios.create({
  baseURL,
});

 

2. axios.interceptors.response를 통해 액세스 토큰 재발급 후 재요청

// 응답을 가로채고 처리하는 인터셉터 설정
api.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    // AccessToken이 만료되었을 경우
    if (error.response.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      // 새로운 AccessToken을 발급받습니다.
      const newAccessToken = await refreshAccessToken();
      // 발급받은 AccessToken으로 요청을 다시 시도합니다.
      originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
      return api(originalRequest);
    }
    return Promise.reject(error);
  }
);

 

첫 번째 인자는 응답이 성공했을 때, 두 번째 인자는 요청이 실패했을 때 실행됩니다. 401 에러를 응답받으면 액세스 토큰을 재발급받은 후 새로운 액세스 토큰으로 요청을 다시 시도합니다.

 

 

또한 요청을 보낼때에도 interceptors 기능을 사용할 수 있습니다.

3. axois.interceptors.request를 통해 headres에 액세스 토큰 설정

// 요청 보낼 때 headers에 accesstoken 추가
api.interceptors.request.use(
  (config) => {
    const accessToken = getAccessToken();
    if (accessToken) {
      config.headers.Authorization = `Bearer ${accessToken}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

 

이렇게 설정하면 api 인스턴스를 통한 요청 시마다 헤더에 액세스 토큰이 자동으로 포함되므로, 요청할 때마다 직접 헤더를 설정할 필요가 없습니다.

 

전체코드

import axios from 'axios';
import {
  getAccessToken,
  getRefreshToken,
  setAccessToken,
  setRefreshToken,
} from './cookie';

const baseURL = process.env.REACT_APP_SERVER_URL;

// api 인스턴스 생성
const api = axios.create({
  baseURL,
});

// 새로운 AccessToken을 발급받는 함수
const refreshAccessToken = async () => {
  const refreshToken = getRefreshToken();
  try {
    const response = await axios.get(`${baseURL}v1/oauth/refresh-token`, {
      headers: {
        Authorization: `Bearer ${refreshToken}`,
      },
    });
    const { accessToken: newAccessToken } = response.data.data;
    setAccessToken(newAccessToken);
    return newAccessToken;
  } catch (error) {
    console.error(error);
  }
};

// 요청 보낼 때 headers에 accesstoken 추가
api.interceptors.request.use(
  (config) => {
    const accessToken = getAccessToken();
    if (accessToken) {
      config.headers.Authorization = `Bearer ${accessToken}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// 응답을 가로채고 처리하는 인터셉터 설정
api.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    // AccessToken이 만료되었을 경우
    if (error.response.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      // 새로운 AccessToken을 발급받습니다.
      const newAccessToken = await refreshAccessToken();
      // 발급받은 AccessToken으로 요청을 다시 시도합니다.
      originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
      return api(originalRequest);
    }
    return Promise.reject(error);
  }
);

export default api;

사용법

import api from 'utils/axios';

const getGameRoomList = async () => {
    try {
      const response = await api.get(`v1/gameRoomList`);
      console.log(response);
    } catch (error) {
      console.error(error);
    }
  };

 

참고 : https://axios-http.com/docs/interceptors

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함