[Vue] Axios 전역 인터셉터 설정

🤔

REST API로 데이터를 불러오고 Vue를 통해 화면단을 구성하면서 Axios를 활용한 비동기통신을 많이 사용하게 된다.

DB 접근을 통한 CRUD는 물론, 화면을 전환할 때마다 API에 요청을 보내 사용자의 인증/인가 여부를 리턴해야 하기 때문이다.

 

기본적으로 요청 URL을 매개인자로 넣어야 하는데 같은 호스트를 매번 적어주어야 하고, 혹시라도 포트번호가 바뀌면 모든 메서드를 수정해야 했다.

뿐만 아니라 인증을 위해 헤더에 토큰 값을 추가하고, 만약 응답에서 토큰이 만료됐다는 결과값을 반환하면 그 결과를 vuex 상태에 저장하고...

같은 작업을 반복적으로 하는 것이 비효율적으로 느껴졌다.

📁 전역 설정

axios는 모든 요청에 공통적으로 적용되는 구성 기본 값(Config default) 설정을 지원한다.

defaults.baseURL

모든 요청에 대해 Priffix를 설정할 수 있다.

각 요청에서 작성한 URL은 지정한 문자열 뒤에 붙어서 전송된다.

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

defaults.headers

모든 요청의 헤더에 포함되는 값을 지정할 수 있다.

예시에서 지정한 토큰은 Authorization이라는 이름으로 헤더에 포함되어 모든 요청에 함께 전송된다.

axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;

intercepters.request.use

요청을 전송하기 전 이를 가로채서 작업을 수행한다.

axios.interceptors.request.use(
    (config) => {
        return config;
    },
    (error) => {
    	return Promise.reject(error);
    }
);

intercepters.response.use

응답을 받은 후 then()에서 작업이 수행되기 전 이를 가로채 작업을 수행한다.

axios.interceptors.response.use(
    (config) => {
        return config
    },
    (error) => {
        return Promise.reject(error);
    }
);

config.globalProperties.axios

설정한 axios를 최상위 뷰 인스턴스에 전역 변수로 설정한다.

// main.js

const app = createApp(App);
app.config.globalProperties.axios = axios;

app.use(router).use(store).mount('#app');

 

이제 컴포넌트에서 다음과 같이 axios를 사용할 수 있다.

// VueComponent.vue

this.axios.post("/route");

📁 사용자 정의 설정

때로는 전역적으로 설정한 URL이나 인터셉터, 헤더를 사용하고 싶지 않은 경우도 있다.

이럴 때에는 글로벌 설정의 영향을 받지 않는 독립적인 axios 객체를 사용하면 된다.

// customAxoisConfig.js

const instance = axios.create({
	// base URL
	baseURL: 'https://api.example.com'
});
// 요청 인터셉터
instance.interceptors.request.use(/**/);
// 응답 인터셉터
instance.interceptors.response.use(/**/);

 

컴포넌트에서 다음과 같이 axios 통신을 보내면, 객체를 통해 선언한 지역 설정이 반영된다.

// VueComponent.vue

this.axios.post("/route");

✏️ 적용하기

나는 요청 헤더에 토큰을 포함시키기 위해 다음과 같이 요청 인터셉터를 작성하고 전역 설정했다.

axios.defaults.headers는 처음 한번만 수행되기 때문에, vuex 상태에 변경이 발생해도 이를 감지하지 못한다.

로그아웃 등 토큰에 변경이 생기면 헤더에 즉각 반영되어야 하기 때문에, 매 요청마다 상태를 새로 받아오는 인터셉터를 통해 로직을 구현한 것이다.

// 요청을 보낼 때 상태에 저장된 token을 함께 전송
axios.interceptors.request.use(
    (config) => {
        config.headers.token = store.state.auth.token;
        return config;
    },
);

 

응답을 받을 때마다 매번 토큰과 사용자 정보를 헤더에 저장하도록 했다.

토큰이 만료되면 그에 해당하는 커스텀 코드를 반환하도록 만들어 사용자에게 로그아웃되었음을 알리도록 구현했다.

axios.interceptors.response.use(
    (config) => {
        // 토큰 저장
        store.commit("auth/setToken", config.headers.token);
        // 사용자 정보 저장
        store.commit("auth/setUser", config.headers.user==null ? null : JSON.parse(config.headers.user));

        if(config.headers.auth=="IS_EXPIRED") {
            store.commit("auth/logout");
            alert("오랫동안 접속하지 않아 로그아웃 되었어요🥺");
            router.push({ path: '/login' });
        }
        return config
    },
    (error) => {
        console.log(error);
    }
);