비동기통신[Axios & Fetch]

October 17, 2022

목차


Fetch와 Axios 간단소개

Fetch API는 네트워크 요청을 위해 fetch()라는 메서드를 제공하는 인터페이스입니다. 모던 브라우저에 내장되어 있어 따로 설치할 필요가 없습니다. 또한 node.js의 실험적 기능을 활성화하여 사용할 수 있습니다.

Axios는 서드파티 라이브러리로 CDN 또는 npm, yarn과 같은 패키지 매니저를 통해 설치하여 프로젝트에 추가할 수 있습니다. Axios는 브라우저 또는 node.js 환경에서 실행할 수 있습니다.

Fetch 와 axios는 둘다 promise 기반의 HTTP 클라이언트입니다. 즉 이 클라이언트를 이용해 네트워크 요청을 하면 이행(resolve)또는 거부(reject)할 수 있는 promise가 반환됩니다.


Axios 설치 방법

node.js 환경에서 Axios를 사용하는 경우 다음 설치 방법 중 하나를 사용할 수 있습니다.

  • NPM을 사용하여 설치:

npm install axios

  • Yarn을 사용하여 설치:

yarn add axios

설치 한 다음 프로젝트로 임포트 합니다

import axios from "axios";
  • 브라우저 내에서 Axios를 사용하는 경우 CDN을 사용할 수 있습니다.
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

Fetch와 Axios의 기능 비교


문법(Syntax)

1. Fetch API

  • 두 개의 인자를 받습니다. 첫 번째 인자는 가져오려는 리소스의 URL입니다. 두 번째 인자는 요청을 만들기 위한 구성 옵션을 포함하는 객체인 선택적 인자입니다. 아래와 같이 구성 옵션이 없으면 요청은 기본적으로 GET 요청을 하도록 설정됩니다.
fetch(url);
  • 구성 옵션을 사용하면 다음을 포함하는 요청에 대한 몇 가지 사용자 지정 설정을 정의할 수 있습니다.
fetch(url, {
  method: "GET", // 다른 옵션들: (POST, PUT, DELETE, etc.)
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({}),
});

2. Axios

  • Fetch API문법과 비슷하나, 다양한 방법으로 호출할 수 있습니다.
axios(url, {
  // 설정 옵션
});
  • 아래와 같이 HTTP 메서드[get,post,put etc…]를 붙일 수도 있습니다.
axios.get(url, {
  // 설정 옵션
});
  • fetch 메서드와 마찬가지로 axios의 HTTP 메서드를 무시하여 다음과 같이 기본적으로 GET 요청으로 설정할 수 있습니다.
axios(url);
  • 마찬가지로 두 번째 인자를 사용하여 요청에 대한 몇 가지 사용자 지정 설정을 정의할 수 있습니다.
axios(url, {
  method: "get", // 다른 옵션들 : (post, put, delete, etc.)
  headers: {},
  data: {},
});
  • 아래와 같이 작성할 수도 있습니다.
axios({
  method: "get",
  url: url,
  headers: {},
  data: {},
});

이제 Axios와 Fetch가 응답 처리 시 어떤 차이가 있는지 보겠습니다.


JSON 데이터 처리

아래 예시에서는 JSONPlaceholder라는 REST API에 GET 요청을 통해 Todo리스트를 가져오고 차이점을 비교합니다.

1. Fetch API

const url = "https://jsonplaceholder.typicode.com/todos";

fetch(url)
  .then((response) => response.json())
  .then(console.log);
  • fetch()는 .then() 메서드에서 처리된 promise를 반환합니다.
  • 이 시점에서 필요한 JSON 데이터 형식이 없으므로 response객체에서 .json()메서드를 호출합니다.
  • 이것은 JSON 형식의 데이터로 해결되는 또 다른 promise를 반환합니다.
  • 따라서 일반적인 fetch request contains에는 두 번의 .then()을 호출합니다.

2. Axios

const url = "https://jsonplaceholder.typicode.com/todos";

axios.get(url).then((response) => console.log(response.data));
  • Axios를 사용하면 response 데이터를 기본적으로 JSON 타입으로 사용할 수 있습니다. response 데이터는 언제나 response 객체의 data 프로퍼티에서 사용할 수 있습니다.
axios.get(url, {
  responseType: "json", // 옵션들: 'arraybuffer', 'document', 'blob', 'text', 'stream'
});
  • 다음과 같이 구성 옵션[responseType]을 지정하여 기본 JSON 데이터 유형을 재정의할 수 있습니다.

ALT fetch-axios

  • 브라우저 콘솔창에 출력된 결과는 위와 같습니다. (fetch & axios 출력 결과 동일)

자동 문자열화(stringify)

이제 JSONPlaceholder API를 사용하여 데이터를 전송해 보겠습니다.

이를 수행하려면 데이터를 JSON 문자열로 직렬화해야 합니다. 메서드를 사용하여 JavaScript 객체를 API에 보낼 때 POST Axios는 자동으로 데이터를 문자열화합니다.

1. Fetch API

  • Fetch API를 사용하는 경우 수동으로 JSON.stringify()사용해서 객체를 문자열화 한 다음 body할당해야 합니다.
  • 그리고 Fetch를 사용하면 명시적으로 Content-Type을 application/json으로 설정해야 합니다.
const url = "https://jsonplaceholder.typicode.com/todos";

const todo = {
  title: "A new todo",
  completed: false,
};

fetch(url, {
  method: "post",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify(todo),
})
  .then((response) => response.json())
  .then((data) => console.log(data));
  • fetch 응답 결과

    ALT response-result

2. Axios

  • axios post메서드로 data를 요청할 때 데이터 속성에 요청 본문으로 보낼 대상을 할당합니다.
  • Content-Type을 설정할 수도 있습니다. 기본적으로 axios는 Content-Type을 application/json으로 설정합니다.(Content-Type이 application/json일 때 생략가능)
const url = "https://jsonplaceholder.typicode.com/todos";

const todo = {
  title: "A new todo",
  completed: false,
};

axios
  .post(url, {
    // headers: {
    //   "Content-Type": "application/json",
    // },
    data: todo,
  })
  .then((response) => console.log(response.data));

response객체를 살펴보겠습니다.

ALT fetch-axios

응답 데이터는 response.data와 같은 위치에 있습니다.

ALT response-result


에러 처리

Fetch와 axios는 모두 이행(resolve)되거나 거부(reject)된 promise를 반환합니다. Promise가 거부(reject)되면 .catch()를 사용하여 에러를 처리할 수 있습니다. Axios로 에러를 처리하는 방법은 Fetch에 비해 더 간결합니다.

1. Fetch API

  • Fetch는 404 에러나 다른 HTTP 에러 응답을 받았다고 해서 promise를 거부(reject)하지 않습니다.
  • Fetch는 네트워크 장애가 발생한 경우에만 promise를 거부(reject)합니다. 따라서 .then()을 사용해 수동으로 HTTP 에러를 처리해야 합니다.

다음 코드를 살펴보겠습니다.

const url = "https://jsonplaceholder.typicode.com/todos";

fetch(url)
  .then((response) => {
    if (!response.ok) {
      throw new Error(
        `This is an HTTP error: The status is ${response.status}`
      );
    }
    return response.json();
  })
  .then(console.log)
  .catch((err) => {
    console.log(err.message);
  });
  • response블록에서 response의 ok 상태가 false인 경우 .catch()에서 처리되는 커스텀 에러를 발생시킵니다.

ALT fetch-axios

위 예시는 fetch가 성공했을 때의 스크린샷입니다. 만약 잘못된 URL 엔드포인트를 요청했을 경우 ok와 status 속성은 각각 false와 404값을 가지게 됩니다. 이에 에러를 발생시키고 .catch()절에서 커스텀 에러 메세지를 출력합니다.

2. Axios

axios의 .catch()를 사용한 일반적인 에러 처리는 다음과 같습니다.

const url = "https://jsonplaceholder.typicode.com/todos";

axios
  .get(url)
  .then((response) => console.log(response.data))
  .catch((err) => {
    console.log(err.message);
  });
  • Axios의 promise는 상태 코드가 2xx 범위를 벗어나면 거부(reject)합니다. response err 객체에 다음과 같은 request속성이 포함되어 있는지 확인하여 에러에 대한 자세한 정보를 확인할 수 있습니다 .
.catch((err) => {
  // 에러 처리
  if (err.response) {
    // 요청이 이루어졌고 서버가 응답했을 경우

    const { status, config } = err.response;

    if (status === 404) {
      console.log(`${config.url} not found`);
    }
    if (status === 500) {
      console.log("Server error");
    }
  } else if (err.request) {
    // 요청이 이루어졌으나 서버에서 응답이 없었을 경우
    console.log("Error", err.message);
  } else {
    // 그 외 다른 에러
    console.log("Error", err.message);
  }
});
  • 에러 객체의 response 프로퍼티는 클라이언트가 2xx 범위를 벗어나는 상태 코드를 가진 에러 응답을 받았음을 나타냅니다.
  • 에러 객체의 request 프로퍼티는 요청이 수행되었지만 클라이언트가 응답을 받지 못했음을 나타냅니다.
  • 요청 또는 응답 속성이 모두 없는 경우는 네트워크 요청을 설정하는 동안 에러가 발생한 경우입니다.

응답 시간 초과 / 취소 요청

각각의 HTTP 클라이언트에서 HTTP 요청이 시간 초과될 경우 어떻게 처리하는지 살펴봅시다.

1. Fetch API

Fetch를 통한 요청을 취소하기 위해서는 AbortController 인터페이스를 사용할 수 있습니다. 다음과 같이 사용할 수 있습니다.

const url = "https://jsonplaceholder.typicode.com/todos";

const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => controller.abort(), 4000);

fetch(url, {
  signal: signal,
})
  .then((response) => response.json())
  .then(console.log)
  .catch((err) => {
    console.error(err.message);
  });
  • controller객체를 생성하고나서 signal객체와 abort()메서드에 접근합니다.
  • 이 signal객체를 설정 옵션을 통해 fetch()에 넘깁니다.
  • 이렇게 하면 abort()메서드가 호출될 때마다 fetch요청이 종료됩니다.
  • 그리고 setTimeout기능을 사용하여 서버가 4초 이내에 응답하지 않으면 작업이 종료됩니다.

2. Axios

Axios에서는 timeout 속성을 설정 객체에 추가하여 요청이 종료될 때까지의 시간을 밀리초로 지정할 수 있습니다.

다음 코드에서는 만약 요청이 4초 이상 걸릴 경우에 종료하고 console에 에러 로그를 남기게 하고 있습니다.

const url = "https://jsonplaceholder.typicode.com/todos";

axios
  .get(url, {
    timeout: 4000, // 기본 설정은 '0'입니다 (타임아웃 X)
  })
  .then((response) => console.log(response.data))
  .catch((err) => {
    console.log(err.message);
  });

참고자료

  1. Axios vs Fetch for beginners

Written by @YeonJun Kim

넥스트이노베이션의 기술, 문화, 뉴스, 행사 등 최신 소식 및 넥스트이노베이션이 겪은 다양한 경험을 공유합니다.