본문 바로가기
Vue.js

[Vue.js] 21. axios interceptors

by 청양호박이 2021. 4. 27.

Spring Boot에서 기존에 JWT를 통한 인증을 포함하는 RestAPI를 구현할 때, Interceptor라는 것이 있었습니다. 이 기능은 httpRequest와 httpResponse를 진행하기 전에 잠시 application에서 가로채서 특정 동작을 수행 후 다시 동작을 수행하게 해주는 기능입니다.

 

Spring Boot에서는 HandlerInterceptor interface를 implements하고 관련된 method를 @Override하여 사용했습니다. Controller에서 해당 요청을 처리하기 전에 동작하는 preHandle( ), 이후에 동작하는 postHandle( ) 이런식으로 구성이 되어 있습니다. 

 

그렇다면, SPA를 제공하는 vue.js와 같은 곳에서는 이런 기능을 사용할 수 없을까요?? 물론 사용할 수 있습니다. 이렇게 하는 로직에는 항상 어딘가 뭔가를 요청하고 받는동작이 포함되고, 이를 가능하게 하여야 하기 때문에... 적합한 plugin이 있습니다. 바로 axios입니다. 이 axios는 promise기반의 비동기처리하는 녀석임은 기존에도 별도로 글을 작성했던 적이 있었습니다. 

 

이 axios에서도 위에 언급했던 interceptor를 제공하고 있습니다. 그렇다면 공식 docs를 참고하여 axios.interceptors를 내 web application에 전역으로 설정하여 구성하겠습니다. 

 

 

1. 현재 axios 적용 분석


현재 web application의 생김새는 다음과 같습니다. 우선 main.js에 axios를 import하여 Front-End와 Back-End의 분리구성으로 인한 baseURL을 default로 설정했습니다. 

 

[src > main.js]

import Vue from 'vue';
import vuetify from '@/plugins/vuetify';
import axios from 'axios';
import App from './App';
import router from './router';

Vue.config.productionTip = false;

// baseURL 기본값을 정의한다
axios.defaults.baseURL = 'http://localhost:8888/';

new Vue({
  el: '#app',
  vuetify,
  router,
  components: { App },
  template: '<App/>',
});

그리고 나머지 components의 axios에서 필요한 부분은 methods자체적으로 사전에 체크하여 구성하고, then을 통해서 온 답변을 가공하는 방식을 사용합니다. 물론 공통적으로 적용이 필요한 부분이 있습니다. 예를 들어서 Header를 설정한다던지... 그런 코드는 매 vue 파일내 axios부분에 반복적으로 들어가게 됩니다. 

 

[개별 vue 코드에 axios가 포함된 부분]

      const decodeAccessToken = jwt.decode(storage.getItem('at-jwt-access-token'));
      let headers = null;
      if(decodeAccessToken.exp < Date.now()/1000 + 60){
        console.log('만료됨!!');
        headers = {
          'at-jwt-access-token': storage.getItem('at-jwt-access-token'),
          'at-jwt-refresh-token': storage.getItem('at-jwt-refresh-token'),
        }
        console.log('headers : ', headers);
      }else{
        console.log('만료되지않음!!');
        headers = {
          'at-jwt-access-token': storage.getItem('at-jwt-access-token'),
        }
        console.log('headers : ', headers);
      }
      axios.get('/qss/list', {
        headers: headers,
      }).then((res) => {
        if(res.headers['at-jwt-access-token'] != null && res.headers['at-jwt-access-token'] != storage.getItem('at-jwt-access-token')){
          storage.setItem('at-jwt-access-token', "");
          storage.setItem('at-jwt-access-token', res.headers['at-jwt-access-token']);
          console.log("Access Token을 교체합니다!!!")
        }
      }).catch((error) => {
        // eslint-disable-next-line
        console.log(error);
      }).then(() => {
        // eslint-disable-next-line
      });

 

뭔가 비효율 적이죠?? 이번 부분은 딱 interceptor에서 해결해주기 좋은 부분이네요...

 

 

2. axios interceptor 적용


interceptor는 모든 소스 내 axios가 들어간 부분에 공통적으로 적용이 되어야 합니다. 따라서 global config를 해줘야 합니다. 이를 위해서, 우선 신규 js파일을 생성합니다. 

 

[axios.js]

import axios from 'axios';

axios.defaults.baseURL = 'http://localhost:8888/';

// Add a request interceptor
axios.interceptors.request.use(function (config) {
  // Do something before request is sent
  console.log('request interceptor!!!!')
  return config;
}, function (error) {
  // Do something with request error
  return Promise.reject(error);
});

// Add a response interceptor
axios.interceptors.response.use(function (response) {
  // Any status code that lie within the range of 2xx cause this function to trigger
  // Do something with response data
  console.log('response interceptor!!!!')
  return response;
}, function (error) {
  // Any status codes that falls outside the range of 2xx cause this function to trigger
  // Do something with response error
  return Promise.reject(error);
});

export default axios;

기존에 vuetify를 적용한 방식과 유사합니다. 관련 plugin을 import해주고 defaults config를 포함하여, request, response 에 해당하는 interceptors도 포함하여 제작합니다. 

 

[파일위치]

다음과 같이 plugins라고 생성된 폴더에 추가해 줍니다. 해당 위치를 기준으로 main.js에 추가해 주면 됩니다.

 

[src > main.js]

import Vue from 'vue';
import vuetify from '@/plugins/vuetify';
import axios from  '@/plugins/axios';
import App from './App';
import router from './router';

Vue.config.productionTip = false;

new Vue({
  el: '#app',
  vuetify,
  router,
  components: { App },
  template: '<App/>',
});

기존하고 변경된 부분이 보이시나요?? 기존에는 axios를 import할때 plugin자체를 대상으로 하였지만, 이번에는 새로 추가한 axios.js를 import하였습니다. 그리고, 기존에 설정했던 axios.defaults.baseURL도 모두 제거했습니다. 정말 단순하게 이렇게 종료 되었습니다. 

 

 

3. 확인


아무 component내 vue파일에 들어가서 axios call을 진행해 보면 다음과 같습니다.

axios.js?847e:8 request interceptor!!!!
axios.js?847e:19 response interceptor!!!!

우선 interceptor는 정상적으로 거쳐서 axios call이 진행됨을 확인하였습니다. 그렇다면 기존에 코드에 대한 변경도 궁금하실텐데... 해당 부분은 현재 작성중인 [Spring Boot] 34. JWT 인증 갱신처리 (4) 에서 확인하실 수 있습니다... ^ ^

 

- Ayotera Lab -

댓글