fetch() vs axios()

leitmotif·2021년 12월 20일
0

Frontend 기초 공부

목록 보기
4/4

개요

Frontend와 Backend는 떨어뜨릴 수 없는 관계입니다.

마치 해수면 같달까요? 물 밑에서 든든하게 작업해주는 백엔드와

물 위에서 그것을 잘 보여주는 프론트엔드같기도 합니다.

그렇듯 프론트엔드와 백엔드는 서로 통신하게 되는데

자바스크립트에서는 내장된 Fetch 함수를 쓰거나, 혹은 axios 패키지를 쓰곤 합니다.

저는 큰 생각없이 axios를 써오곤 했는데, 왜 fetch가 아닌 axios를 쓰느냐? 라고 누군가 물어본다면 바로 대답이 나오지 않을 것 같습니다.

그 계기로 fetch와 axios가 어떤 차이를 가지고 있는지 알아보았습니다.


Need to download?

개요에 적었듯 fetch 함수는 Javascript ES6부터 지원하는 내장형 통신 함수입니다.

그에 반해 axios는 npm을 이용해 패키지를 내려받아야 사용가능합니다.

내장된 함수를 그냥 쓰면 되는 거 아닌가?

에 대한 생각이 드는데, '굳이' axios를 다운받아서 쓰는 이유가 있을 겁니다.

그것이 아니라면 js bundle의 양을 줄이기 위해 axios를 사용하지 않아도 되겠다! 라는 생각이 듭니다.

Compatibility?

fetch : Chrome 42+, FireFox 39+, Edge 14+, Safari 10.1+
axios : fetch보다 더 많은 브라우저에도 지원가능함

우선 여기에서 axios의 장점이 나옵니다.

물론 대부분(?)의 컴퓨터 유저분들은 크롬....을 쓰겠지만

axios는 fetch에 비해 많은 브라우저를 지원하기 때문에

경우에 따라 특수한 브라우저를 사용하는 경우엔 axios를 쓸 수 밖에 없는 상황이 나올 것 같습니다.

Data Types

fetch : body로 전달되며, 문자열형태로 전달됨.
axios : data로 전달되며, 자동으로 JSON으로 변환함.

fetch 함수는 응답을 Promise 객체로 가져다줍니다.

응답을 정상적으로 받은 경우 .then()을 통해 객체를 컨트롤할 수 있도록 코드가 짜여집니다.

fetch(url,{method})
.then() <- promise가 잘 받아와졌는지 확인
.then() <- promise가 잘 왔다면 여기 있는 작업을 실행한다.

덧붙여, 첫 번째 then()에서

.then(res => res.json())

을 통해 전달받은 문자열 데이터를 json 데이터로 변환할 수 있습니다.

그와 반해, axios는 객체의 데이터를 바로 json으로 받아옵니다.

axios.get(url)
.then(res => {
  res.data  <- JSON 형태로 들어온다!
})

알고리즘을 풀어볼 때나, 혹은 간단한 웹 서비스를 만들 때 종종

{key:value} 형태의 자료형을 자주 쓰게 됩니다.

이런 부분에서 소소하지만 fetch보단 axios를 선택한 이유 중 하나가 될 듯 합니다.

Response state

axios는 응답에 status code와 status text 두 개가 전달되지만

fetch는 'OK' 속성이 포함됐는지, 아닌지만 판별합니다.

https://http.cat/

자주 쓰는 status code에 따른 고양이 이미지 사이트입니다.

위의 사이트에서도 볼 수 있듯이 어떠한 요청에 따른 응답이 굉장히 많고

오류가 발생하거나, 예외 등으로 인한 '200' status code가 아닌 다른 코드가 발생했을 때

fetch를 쓰면 단순히 오류가 떴구나~ 정도만 알 수 있겠지만

axios는 코드를 통해 디버깅을 하기 전, 어느정도 유추할 수 있을 것이다 라는 생각이 듭니다.

CSRF(XSRF) Issue

프론트엔드 개발자들이 기본적으로 생각해야될 것이 이 CSRF인 것 같습니다.

손쉽게 Input 값을 바꾼다거나...특정 element를 삽입하여 악성 작업을 서버로 하여금 유도시켜

부적절한 행동이 발생시키는데, 놀랍게도 axios는 그것을 자체 설정을 통해 방지할 수 있다고 합니다.

axios.defaults.xsrfCookieName = 'csrftoken';
axios.defaults.xsrfHeaderName = 'X-CSRFTOKEN';

위와 같이 CSRF Token을 저장할 쿠키와 헤더의 이름만 설정해주면 됩니다.

이렇게 생성될 CSRF Token은 Client의 request header, cookie에 담겨져 api를 호출하게 되며

서버는 단순히 토큰이 담겨있는지만 요청으로부터 확인하고 실행할 요청을 거를 수 있습니다.

반면 fetch()는 이러한 보안적인 추가 기능이 없습니다.

Download

axios는 response-type을 blob으로 지정하고 후 처리를 통해 파일 다운로드가 가능합니다.

(엑셀의 경우, ArrayBuffer로 지정합니다.)

axios({
    url: 'http://api.dev/file-download', //your url
    method: 'GET',
    responseType: 'blob', // important
}).then((response) => {
    const url = window.URL.createObjectURL(new Blob([response.data]));
    const link = document.createElement('a');
    link.href = url;
    link.setAttribute('download', 'file.pdf'); //or any other extension
    document.body.appendChild(link);
    link.click();
});

예시는 위와 같습니다.

이를테면 게시글에 있는 첨부 파일을 다운로드 받고 싶다! 라고 한다면

API 호출을 통해 서버에서 다운로드 Stream을 프론트로 전달하고

그를 받은 프론트는 Stream을 Blob 객체로 변환해 다운로드받게끔 하는

그러한 동작인 것 같습니다.

서버에 들어있는 데이터를 다운받게 해야된다고 할 때
서버 측에서 해당 파일의 경로를 찾아 res.download를 보내 구현했던
기억이 있는데, 무엇이 다른지 확인해야겠습니다.

Timeout

서버에 트래픽이 몰렸거나, 혹은 꺼졌다던가... 하는 경우에는

어떤 요청이든 응답이 오지 않는 경우가 있습니다.

axios는 이 때 Timeout을 지정해줄 수 있습니다.

const instance = axios.create({
  baseURL: 'https://some-domain.com/api/',
  timeout: 1000
});

Interceptor

axios는 요청에 대한 Intercept를 제공합니다.

잠깐 이에 대한 이해가 지지부진했는데... 저의 말로 풀어본다면

매번 axios 호출하기 귀찮으니
일단 axios는 불러놓고, 요청이 들어가기 직전에
중간에 어떤 요청을 할지 알려주는 무언가가 있으면 좋겠다!

이럴 때 쓰면 좋은 기능인 듯 합니다.

이를테면

axios.post('/v0/api/login',body)
...
axios.post('/v0/api/register',body)
...
axios.get('/v0/api/getSession')

이런 식으로 매번 어떠한 작업에 대한 요청을 작성하기 보다

const instance = axios.create({
 baseURL:'v0/api',
 timeout:1000
})

이렇게 먼저 axios 객체를 만든 뒤

instance.interceptors.request.use(
  function (config) {
    config.headers["Content-Type"] = "application/json; charset=utf-8";
    config.headers["Authorization"] = " 토큰 값";
    return config;
  },
  function (error) {
    console.log(error);
    return Promise.reject(error);
  }
);

요청에 대한 type, 인가 토큰 값 등을 설정하고 error의 예외 처리를 적용하고

instance.interceptors.response.use(
  function (response) {
    console.log(response);
    return response.data.data;
  },
  function (error) {
    errorController(error);
  }
);

응답이 발생하면 그에 맞는 예외처리를 해 놓은 상태로 두고

export default instance

를 통해 axios 객체를 export 시키면 다른 파일에서 가져다 사용합니다.

import axiosController from './axiosController'
axiosController({
 url:'/login',
 method:'get',
 data:data
})

이러한 구성을 통해 기준이 되는 api의 헤더나 타입이 통일되어있다면

굳이 매번 axios.get.... axios.post.... 등을 써가며 코드의 길이를 늘리지 않아도 되고 가독성 또한 향상되는 것이 느껴집니다.

당연하게도(?) fetch()는 이와 같은 기능이 없습니다.

그래서, 뭐가 더 낫냐고?

위를 다시 읽어보니 마치 axios의 장점만 늘어놓은 것만 같은 기분입니다.

그래도 fetch()는 내장되어 있기에 따로 다운로드 받을 필요가 없고

또한 기타 환경들의 변화에 대해 영향을 받지 않을 것이기에

이것저것 기능의 이용없이 단순히 데이터를 가져온다던가 하는 경우에 대해서는 fetch()가 유리할 것으로 느껴집니다.

다만 그 외, 서비스를 요청하는 등의 Complex한 문제에 대해서는

axios가 비교불가능할 정도로 유용하다는 체감이 있습니다.

fetch()를 쓴다면 CSRF 방어책을 작성해야되고,

자료형 또한 신경써야되고... 무언가 추가적인 코드를 많이 써야될 것 같은 기분이 드는데

axios는 '이미 우린 네가 원하는 기능이 다 있어!' 라고 말해주는 것만 같습니다.

하지만 axios는 package이기 때문에 기준이 되는 언어의 버전에 맞게 업데이트가 진행되어야하는데

react-native처럼 업데이트가 잦은 라이브러리에 대한 속도를 쫓기 힘든 경우에는 fetch의 사용이 안정적이라는 이야기가 있습니다.


마무리

실은 axios를 사용하면서

CSRF, Timeout, Interceptor 기능은 모르고 사용했습니다.

코드를 더 편하게 작성할 수 있다!!! 하는 성취감도 있고

뭣도 모르고 그동안 써온 거 아닌가?! 하는 반성도 느끼는

오묘한 기분으로 포스팅을 마칩니다.

profile
제가 그린 것으로 하여금, 동기를 일으키는 개발자가 되고 싶습니다.

0개의 댓글