AJAX란 무엇이고, 비동기 통신 API fetch, axios는 어떻게 쓰이는가

AJAX란?
- JavaScript를 이용한 비동기 통신
- 클라이언트와 서버간에 XML, JSON 데이터를 주고받는 기술이다.
- AJAX는 기술 자체를 뜻하기 보단, HTML, XHTML, CSS, JavaScript, DOM, XML, XSLT, XMLHttpRequest 오브젝트들이 조합한 기술의 총칭을 일컫는다.
- XMLHttpRequest 객체를 이용해서, 페이지 새로고침 없이 페이지의 일부만을 위한 데이터를 로드하는 기법이다.
- AJAX(Asynchronous JavaScript and XML)의 X는 XML을 뜻하지만, JSON이 더 가볍고, 자바스크립트의 오브젝트로 쉽게 변환된다는 점 때문에 XML 보다 많이 사용된다.
AJAX를 사용하는 이유
- 화면에서 무언가 부르거나 데이터를 조회하고 싶을 경우, 페이지 전체를 새로고침하지 않기 위해 사용한다.
- HTTP 프로토콜은 클라이언트쪽에서 Request를 보내고 서버쪽에서 Response를 받으면 이어졌던 연결이 끊기게 되어있다. 그래서 화면의 내용을 갱신하기 위해서는 다시 request를 하고 response를 하며 페이지 전체를 갱신하게 되며, 이는 엄청난 자원낭비와 시간낭비를 초래하고 말 것이다.
- 하지만 XMLHttpRequest 객체를 통해 서버에 request 하는 경우, JSON이나 XML형태로 필요한 데이터만 받아 갱신하기 때문에 그만큼의 자원과 시간을 아낄 수 있다.
AJAX의 장점
- 웹 페이지의 속도 향상
- 서버의 처리가 완료될 때까지 기다리지 않고 처리가 가능하다.
- 서버에서 Data만 전송하면 되므로 전체적인 코딩의 양이 줄어든다.
- 기존 웹에서는 불가능했던 다양한 UI를 가능하게 해준다. (사진의 제목이나 태그를 페이지의 리로드 없이 수정가능)
AJAX의 단점
- 히스토리 관리가 되지 않는다.
- 페이지 이동없는 통신으로 인한 보안상의 문제가 있다.
- XMLHttpRequest를 통해 통신하는 경우, 사용자에게 아무런 진행 정보가 주어지지 않는다.
= 요청이 완료되지 않았는데 사용자가 페이지를 떠나거나 오작동할 우려가 발생하게 된다. - HTTP 클라이언트의 기능이 한정되어 있다.
- AJAX를 쓸 수 없는 브라우저에 대한 문제 이슈가 있다.
- Script로 작성되므로 디버깅이 용이하지 않다.
- 동일-출처 정책으로 인하여 다른 도메인과는 통신이 불가능하다. (Cross-Domain문제)
XMLHttpRequest API인 Axios와 Fetch 소개

비동기 통신의 목적
- 페이지를 리로딩하지 않고 컨텐츠만 바뀌게 하기위해 API 통신을 한다.
- API를 사용함으로써 랜더링 없이 컨트롤러로만으로도 데이터베이스를 수정할 수 있다.
fetch
- 원격 API를 간편하게 호출하는 Built-in API로 별도의 설치 없이 모던 브라우저에서 사용할 수 있는 함수이다.
- window 객체에 정의되어 있으며, HTTP Pipeline(Request/Response)를 위한 Javascript Interface이다.
fetch 탄생 과정
- 클라이언트 단에서 직접 http요청 응답받는 과정은 매우 복잡했다.
- 라이브러리 도움을 받으면 번들러 크기 가중됐다.
- 내장함수 fetch 등장
fetch('URL' [, OptionObj]) => Promise
fetch 함수의 리턴 값은 Promise객체다.
API 호출이 성공했을 경우에는 응답(response) 객체를 resolve하고, 실패했을 경우에는 error 객체를 reject한다.
fetch('https://jsonplaceholder.typicode.com/posts/1').then((response) =>
console.log(response)
);
// Response {status: 200, ok: true, redirected: false, type: "cors",
1) GET 호출
대부분의 REST API들은 JSON 형태의 데이터를 응답한다. 응답(response) 객체는 json() 메서드를 제공한다. 이를 통해 JSON 포멧의 응답 전문을 자바스크립트 객체로 변환하여 얻을 수 있다.
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => response.json())
.then((data) => console.log(data));
// { "userId": 1, "id": 1, "title": "hi"}
2) POST 호출
원격 API에서 관리하고 있는 데이터를 생성해야 한다면, 요청 전문(보낼 내용, req.body에 들어갈 내용) 포함할 수 있는 POST 방식의 HTTP 통신이 필요하다.
- method 옵션을 POST로 지정해주고,
- headers 옵션을 통해 JSON 포멧을 사용한다고 알려줘야 하며,
- body 옵션에 요청 전문을 JSON 포멧으로 직렬화화여 설정해준다.
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'Test', body: 'I am testing!', userId: 1 }),
}).then((response) => console.log(response));
// Response {
// type: "cors",
// url: "https://jsonplaceholder.typicode.com/posts",
// redirected: false, status: 201, ok: true,
// … }
응답 객체의 json() 메서드를 호출하면 응답 전문을 객체 형태로 얻을 수 있다.
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'Test', body: 'I am testing!', userId: 1 }),
})
.then((response) => response.json())
.then((data) => console.log(data));
// {title: "Test", body: "I am testing!", userId: 1, id: 101}
Node 코드 예시
videoPlayer.addEventListener("ended", ()=>registerView());
const registerView = () => {
const videoId = window.location.href.split("/videos/")[1];
fetch(`/api/${videoId}/view`, { method: "POST", }
}
apiRouter.post(routes.registerView, postRegisterView);
const postRegisterView = async (req, res) => {
const {
params: { id },
} = req;
try {
const video = await Video.findById(id);
video.views += 1;
video.save();
res.status(200);
} catch (error) {
res.status(400);
} finally {
res.end();
}
};
[보너스] 사용성 개선
fetch() 함수는 사용법이 아주 간단하지만, 계속 사용하다보면 똑같은 코드가 반복된다.
예를 들어, 응답 데이터를 얻기 위해서 response.json()을 매번 호출하거나, 데이터를 보낼 때, HTTP 요청 헤더에 "Content-Type": "application/json"로 설정해주는 부분은 지루하게 느껴질 수 있다. 기존에 사용하던 라이브러리와 비교해봤을 때, fetch() 함수의 Promise 기반의 API가 좀 투박하다고 느낄 수 있다.
이럴 때는 fetch() 함수를 직접 사용하기 보다는, 본인 입맛에 맞게 별도의 함수나 모듈로 빼서 사용하시기를 추천한다. 나같은 경우에는 프로젝트의 상황에 맞게 다음과 같이 async/await 키워드를 이용하여 HTTP 방식별로 비동기 함수를 작성하고 모듈화하여 사용하곤 한다.
async function post(host, path, body, headers = {}) {
const url = `https://${host}/${path}`;
const options = {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...headers },
body: JSON.stringify(body),
};
const res = await fetch(url, options);
const data = await res.json();
if (res.ok) {
return data;
} else {
throw Error(data);
}
}
post('jsonplaceholder.typicode.com', 'posts', {
title: 'Test',
body: 'I am testing!',
userId: 1,
})
.then((data) => console.log(data))
.catch((error) => console.log(error));
이 방법으로 API 호출하는 것은 기본적으로 브라우저에서만 가능하지만, Node.js 환경에서도 node-fetch나 unfetch와 같은 라이브러리를 사용하면 가능하다. 인터넷 익스플로러에서는 fetch() 함수를 지원하지 않으니 참고해서 사용하자.
Axios
Axios 는 써드파티 라이브러리이다.
브라우저 호환성이 보장되며, 사용하기도 쉬워 많은 개발자들이 사용하고 있다.
React 코드 예시
// $ npm install axios
const getMovies = async () => {
const {
data: {
data: { movies },
},
} = await axios.get(
'https://yts-proxy.nomadcoders1.now.sh/list_movies.json?sort_by=date_added'
);
this.setState({ movies, isLoading: false });
};
axios는 HTTP request 요청을 간소화한다.