3) axios 전역 사용하기 (instance, interceptors) with Vue

2025. 12. 3. 16:01Basic_Code

개요

진행중이던 프로젝트 중간에 투여되어 작업을 진행했던 7개월동안

지속적으로 궁금했던 프로젝트내(vue) axios 관련 통신 구조를 파헤쳐보기로 했다. (공부도 할겸)

 

목차

1. axios

1-1. axios 전역설정

1-2. axios instance 

1-3. axios interceptors

 

1. axios

axios logo

 

axios란 무엇인가? 간단히 설명하고 넘어가자면,

axios는 브라우저, Node.js를 위한 Promise API를 활용하는 HTTP 비동기 통신 라이브러리이며

백엔드와 프론트엔드의 통신을 간결하고 쉽게 진행하기 위해 사용한다.

 

axios의 특징 가운데 이 포스팅에서 우리가 눈여겨 봐야할 것은 아래와 같이 3가지이다.

 

1. 자동으로 JSON데이터 형식으로 변환

2. data 속성을 사용

3. data는 object를 포함한다

4. 요청을 취소할 수 있고 타임아웃 설정 가능

5. HTTP 요청을 가로채기 가능

 

 

- 기본적인 axios 문법 

axios({
  url: 'https://www.abcd.co.kr/api/list', // 통신할 url
  method: 'get', // 통신방식
  data: { // 인자로 보낼 데이터
    foo: 'diary'
  }
});

 

axios 관련 요청 파라미터 예시

 

 

1-1. axios 전역으로 사용하기

과거 개인프로젝트에서는 컴포넌트내 axios를 import 하여 필요시 api 호출에 사용했다면

프로젝트를 진행하면서 api > index.js 에 axios관련 설정을 하고 전역적으로 사용하는 방식을 채택했다.

이러한 방식은 프로젝트 관련 코드 가독성을 높이고 유지보수에도 용이하다는 장점이 있어 한 눈에 axios 관련 통신 파악에 편리했다.

 

과정)

1. axios.instance를 통해 axios관련 설정을 한다 (instance예시의 경우, 1-2. axios instance의 예시를 참조바람)

2. instance 변수를 export default 하여 다른 컴포넌트에서도 사용할 수 있도록 모듈화 시킨다.

3. api > index.js 내에 axios instance를 import하여 사용한다.

4. index.js내에 설정한 변수를 export default 하여 모듈화 시킨다.

5. main.js에 4번 관련 등록을 한다.(4번을 실행한 경우 필요)

 

여기서 4번의 경우는 필요에 따라 추가한다.

재 프로젝트의 경우, axios로 get, post 호출시 공통된 로직을 수행하기 위해 4번을 추가하여 가독성있게 만들었다.

api 파일을 따로 만들어 그곳에서 4번에 만든 모듈을 import 하여 컴포넌트에 사용하면 되도록 설정한 것.

 

 

ex. 4번의 예시인 index.js 파일 (이 예시는 아래에도 지속적으로 나온다)

import axios from "./axiosInstance";
import router from '@/router';
import report from "./module/api-report"; //api관련 주소파일

const api = {
  GET: function(url, param, responseType = null) {
    axios.get(url, param, {responseType: responseType})
      .then((response) => {
        response;
      })
      .catch((error) => {
        error
        router.push({name: 'error', params: {'error': error}});
      });
  },

  POST: function(url, data, callback, config) {
    axios.post(url, data, {headers: config})
       .then((response) => {
        if (callback && callback.success) {
          callback.success(response.data);
        }
      })
      .catch((error) => {
        if (callback && callback.error) {
          callback.error(error);
        }
        router.push({name: 'error', params: {'error': error}});
      });
  },
  report: report,
};

export default api;

 

 

ex. api > report.js내 4번의 변수를 api라는 이름으로 import 하여 사용한 예시

import api from '../index'

const report = {
  getAbcdList(data, callback) {
    api.POST("/getAbcdList", data, callback);
  }
}
export default report;

 

 

ex. 5번의 main.js에 전역으로 등록

import { createApp } from 'vue'
import App from '@/App.vue'
import router from '@/router'
import api from '@/api'
import '@/assets/css/style.scss'


const app = createApp(App)

app.config.globalProperties.$api = api //api 전역등록
app.use(router).mount('#app')

 

 

ex. 컴포넌트내에서 api 사용예시

  getAbcdList() {
      const callback = {
        success: (response) => {
          console.log(response);
          this.abcdList = response.data.map(item => ({
            title: item.abcdName,
            value: item.abcdIdx,
          }));
          this.$nextTick(() => this.autoSeletedList())
        },
        error: (error) => {
          console.log(error);
        }
      }

      this.$api.report.getAbcdList({}, callback);
    },

 

axios 관련 api > index.js내 POST의 공통로직으로 url과 data, callback을 받도록 설정했기 때문에 컴포넌트내 api를 호출해 사용하는 경우 data가 없더라도 {} 빈 객체와 callback을 전달한다. 

 

 

1-2. axios instance 

axios instance를 사용하는 이유는 무엇일까? 

만약, 여러 컴포넌트에서 axios를 호출해 사용하는데 그때마다 공통된 baseUrl을 설정한다면? 

위와 같이 여러 상황에 반복되는 부분이 있을 때 이 부분을 공통화 시킨다면 재사용성이 높아질 것이다.

반복되는 코드를 인스턴스화하여 코드의 가독성과 재사용성을 높이는 것. 그것이 instance를 사용하는 가장 큰 목적일 것이다.

 

일단 instance의 개념을 이해하기 위해서는 객체지향프로그래밍의 클래스와 인스턴스에 대한 개념이해가 요구되어진다.

 

더보기

여기서 객체지향프로그래밍(OOP)이란?

 

소프트웨어를 개발하는 데 사용되는 프로그래밍 패러다임 중 하나로 프로그램을 개체(Object) 중심으로 설계하고

구성하는 방법론이다.

목표 ) 코드를 더 모듈화하고 추상화하여 프로그램의 복잡성을 줄이고 유지보수를 쉽게 만드는 것

 

구성: 클래스 / 인스턴스

클래스(Class): 클래스는 객체를 만들기 위한 일종의 청사진(blueprint) 또는 템플릿(template). 클래스는 객체가 가져야 할 속성(attribute)과 메서드(method)를 정의

인스턴스(Instance): 클래스를 기반으로 만들어진 실제 객체. 클래스의 인스턴스는 클래스에 정의된 속성과 메서드를 가지며, 서로 다른 인스턴스는 독립적으로 상태 관리 가능

 

객체지향프로그래밍은 클래스와 인스턴스로 구성되어있는데, 자주 사용하는 틀을 정의하는 것을 클래스, 그 틀을 기반으로

원하는 구체적인 내용을 넣은 것을 인스턴스라고 이해하면 더 쉽다.

 

Axios에서 사용되는 클래스는 Axios 라이브러리 내부에 정의되어 있으며 HTTP 클라이언트의 기능과 설정을 추상화하는 역할을 한다.

이러한 클래스를 기반으로 사용자는 원하는대로 인스턴스를 생성하여 원하는 속성을 채워줄 수 있는것이다.

이때 속성으로 들어가는 것에는여러가지가 있을 수 있는데 baseURL, header, params등 다양하다.

 

 

1-2-1. 커스텀 인스턴스 만들기: axios.create()

- Axios를 사용할 때 커스텀 인스턴스를 생성하여 인터셉터 적용 가능. 이 방법은 서로 다른 설정이 필요한 여러 API 엔드포인트를 다룰 때 유용

 

axios.instance 만들기 (환경에 따라 baseURL 설정) 

- axiosinstance.js 파일

let baseURL = "/api/"; // 기본은 로컬 환경
if (window.location.hostname === "www.abcd.ef" ||
    window.location.hostname === "dev.abcd.ef" ||
    window.location.hostname === "abcd.ef") {
  baseURL = "/serverback/api/"; // 운영 환경일 경우
}

const axiosInstance = axios.create({
  baseURL,
  timeout: 300000, //타임아웃설정
});

export default axiosInstance;

 

api 폴더만들고 안에 axiosinstance.js 파일 만든다. (api를 위한 인스턴스를 만드는 것이므로, 보통 폴더명은 api라고 짓는다)

폴더의 위치는 src하위이다.

 

 

1-2-2. axios.create() 메서드 설정 옵션

 

1. baseURL: 이 옵션을 사용하면 모든 요청의 기본 URL을 설정할 수 있다. 이후 요청에서 상대적인 URL을 사용할 때 baseURL을 기준으로 요청이 만들어진다.

2. timeout: 요청의 타임아웃 설정. 밀리초 단위로 설정하며, 요청이 지정된 시간 내에 응답하지 않으면 타임아웃으로 처리된다.

3. headers: 요청 헤더를 설정할 수 있는 객체. 이 헤더는 모든 요청에 추가된다.

4. params: 기본적으로 요청에 추가할 쿼리 매개변수를 설정할 수 있다. 이 매개변수는 모든 요청에 자동으로 추가된다.

5. auth: HTTP 기본 인증을 사용할 때 사용자 이름과 비밀번호를 설정할 수 있다.

6. 기타 옵션: axios에서 지원하는 다양한 옵션들이 있다. 예를 들어 withCredentials를 사용하여 요청 시 쿠키를 전송할지 여부를 설정할 수 있다.

 

 

 

만들어진 axios.instance 를 import로 호출하여 사용하기

- axios폴더내 index.js 파일

import axios from "./axiosInstance";
import router from '@/router';

const api = {
  GET: function(url, param, responseType = null) {
    axios.get(url, param, {responseType: responseType})
      .then((response) => {
        response;
      })
      .catch((error) => {
        error
        router.push({name: 'error', params: {'error': error}});
      });
  },

  POST: function(url, data, config) {
    axios.post(url, data, {headers: config})
      .then((response) => {
        response;
      })
      .catch((error) => {
        error
        router.push({name: 'error', params: {'error': error}});
      });
  },
};

export default api;

 

원래 instance를 ./api/axiosinstance.js로 부터 import하고 instance.get()으로 api를 호출해야하는데, instance가 default이기때문에 저렇게 axios라는 이름으로 적고 axios.get()으로 호출해도 정상작동한다.

axios를 사용하여 api 호출시 전역적으로 공통된 로직을 사용하기 위해 위와 같이 구성하였다. 

 

 

 

 

 

 

1-3. axios interceptors

 axios가 가진 interceptor 의 기능은 무엇일까? 이전엔 interceptor를 제외하고 단순한 호출과 응답만을 

다루어보았다면 기존에 있던 코드를 학습하면서 interceptor기능에 대해 파악하기로 하였다.

 

1) axios의 interceptor란? 

- HTTP 요청이나 응답을 가로채서 처리할 수 있는 강력한 기능으로
   이를 통해 요청이 서버로 전송되기 전의 요청이나 응답으로 then/catch 핸들러로 전달되기 전에 코드를 실행할 수 있다.

 

2) axios의 interceptor의 주요특징

특징 설명
요청 전 처리 서버로 요청이 전송되기 전에 코드를 실행
응답 후 처리 서버로부터 응답을 받은 후, then/catch 핸들러로 전달되기 전에 코드를 실행
전역적 설정 모든 요청이나 응답에 대해 일괄적으로 처리
에러 처리 요청이나 응답 과정에서 발생하는 에러를 중앙에서 처리
헤더 수정 요청이나 응답의 헤더를 동적으로 수정
로깅 모든 요청과 응답을 로깅하여 디버깅에 활용
인증 처리 토큰 갱신이나 인증 관련 로직을 중앙에서 처리

 

 

3) axios의 interceptor의 사용예시

 

3-1) 요청 인터셉터: axios.interceptors.request

-  클라이언트에서 API Server로 ‘요청이 전송되기 이전’에 실행될 함수나 ‘요청 과정에서 발생한 오류’에 대해

   인터셉트 하는 것을 의미.

 

3-2) axios.interceptors.request.use() 메서드의 파라미터

 

3-2[1]. onFulfiled : 요청이 전송되기 전에 실행될 함수를 정의. 이 함수는 요청 설정(config) 객체를 인자로 받고,

수정된 설정 객체를 반환.
3-2[2]. onRejected : 요청 과정에서 오류가 발생했을 때 실행될 함수. 
3-2[3]. options : AxiosInterceptorOptions 타입의 추가 옵션을 의미.

 

3-3) axios.interceptors.request.use() 메서드 사용예시

 

- API Server로 요청을 수행하기 전에 요청에 대한 인터셉터 기능을 수행
- 첫 번째 파라미터의 함수의 경우는 API Server로 요청을 전달하기 이전에 수행
- 두 번째 파라미터의 함수의 경우는 API Server로 요청을 보내는 중에 발생하는 오류가 발생할 때 수행

 

axiosInstance.interceptors.request.use(
  (config) => { //첫번째 함수 >> 요청이 전달되기 전에 작업 수행
    const path = location.pathname.toLowerCase();
    const abcdFlag = path.includes("/abcd/") && !path.includes("/abcd/sign");
    const hasInfo = abcdFlag ? store.getters["report/GET_ABCD_INFO"] : store.getters["abcd/GET_ABCD_INFO"];
    const token = hasInfo ? hasInfo.token : null;

    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }

    return config;
  },
  (error) => {Promise.reject(error)} //두번째 함수 >> 요청 오류가 있는 작업 수행 
);

 

 

4. 응답 인터셉터: axios.interceptors.response 

- API Server로부터 응답을 받은 후, then/catch 핸들러로 결과가 전달되기 이전에 인터셉트를 하는 것을 의미

 

4-1. axios.interceptors.response.use() 메서드의 파라미터

 

4-1[1] onFulfilled (성공 콜백)
- 응답이 성공적으로 수신되었을 때 실행되는 함수. 이 함수는 응답 객체를 인자로 받으며, 필요에 따라 응답을 수정하거나 추가 작업을 수행. 수정된 응답 객체를 반환하거나 새로운 응답을 생성.


4-2[2]. onRejected (실패 콜백)
- 응답 수신 중 오류가 발생했을 때 실행되는 함수. 이 함수는 오류 객체를 인자로 받으며, 오류를 처리하거나 추가적인 에러 핸들링 로직을 구현. Promise.reject(error)를 반환하여 오류를 다시 던지거나, 새로운 응답을 생성하여 오류를 복구.

4-3[3]. options
- AxiosInterceptorOptions 타입의 추가 옵션을 의미.

 

 

4-2. axios.interceptors.response.use() 메서드 사용예시

 

- API Server로부터 응답이 들어오는 경우 try/catch가 수행되기 이전에 수행이 되며 이에 대한 인터셉터 기능을 수행.
- 첫 번째 파라미터의 함수의 경우는 API Server로부터 응답이 성공적으로 수신이 되었을 경우 수행.
- 두 번째 파라미터의 함수의 경우는 API Server로부터 응답이 실패하였을 경우 수행.

 

axiosInstance.interceptors.response.use(
  (config) => { // 응답 데이터가 있는 작업 수행
    const userFlag = location.pathname.toLowerCase().includes("/report/");
    const token = config.data.token;

    if (token) {
      if (userFlag) {
        store.commit("report/SET_ABCD_TOKEN", token);
      } else {
        store.commit("abcd/SET_ABCD_TOKEN", token);
      }
    }

    return config;
  },
  (error) => { 	// 응답 오류가 있는 작업 수행
    if (error.response && error.response.status === 403) { // 토큰 만료시 자동 로그아웃 처리
      removeUserInfo();
    }

    return Promise.reject(error);
  }
)