지난 시간에는 자바스크립트는 싱글 스레드 언어인데 어떻게 멀티 스레드 언어인 것처럼 비동기적으로 동작하는지에 대해서 배웠었다. 그 원인은 브라우저 자체에서 지원하는 이벤트 루프라는 원리 떄문에 가능하다는 것을 다시 상기시켜보면 좋을 것 같다.
이 Asynchronous JavaScript and XML
이라는 이름의 Ajax
라는 녀석 또한 마찬가지이다. 자바스크립트가 서버와 통신할 때, 서버에게 데이터를 요청하고 받아올 때 비동기 방식으로 요청하고 받아와 응답받은 웹페이지를 동적으로 갱신하는 프로그래밍 방식이 바로 Ajax이다.
이러한 Ajax는 지난시간의 setTimeout
함수처럼 Web API에서 제공하는 XMLHttpRequest
객체라는 녀석이 존재하기에 가능한 동작이다.
XMLHttpRequest 객체는 HTTP 비동기 통신을 위한 다양한 메서드와 프로퍼티를 제공한다. 오늘은 프로퍼티와 메서드 하나하나가 어떻게 동작하는지 다루기 보다는 전반적인 개념을 다룰 예정이다.
Ajax의 가장 큰 장점은 애플리케이션의 부드러운 화면 전환 효과이다.
기존의 웹페이지는 html 태그부터 시작해서 html 태그로 끝나는 완전한 HTML을 서버로부터 전송받아 웹페이지 전체를 처음부터 다시 렌더링했고 혹여나 HTML이 수정될 경우에는 전체를 다시 리렌더링하는 비효율적인 동작을 감안해야 했다. 고로 깜빡임 현상이 자주 일어났고 이는 사용자 경험의 저하를 유발하는 행위였다.
Ajax는 이러한 점을 보완하여 서버로부터 웹 페이지의 변경에 필요한 데이터만 비동기 방식으로 전송받아 웹페이지를 변경할 필요가 없는 부분은 다시 렌더링하지 않고, 변경할 필요가 있는 부분만 한정적으로 렌더링 하는 방식이 가능해지게 기존에 패러다임을 획기적으로 전환시켰다.
이 때 서버와 주고받는 데이터를 JSON이라는 데이터 포맷으로 통신하는데 JSON이란 또 무엇인지 알아보자.
JSON은 클라이언트와 서버 간의 HTTP 통신을 위한 텍스트 데이터 포맷이다. 자바스크립트와는 종속되지 않는 언어 독립형 데이터 포맷으로, 대부분의 프로그래밍 언어에서 사용할 수 있다.
표기방식은 아래와 같이 객체 리터럴과 유사한 모습이나. 모든 값을 반드시 큰 따옴표로 묶어주어야 한다.
자바스크립트가 Ajax로 서버와 데이터를 주고받기 위해서 JSON의 포맷으로 데이터를 보내야 한다고 배웠다. 헌데 보내야 하는 데이터가 객체이거나 배열이라면 어떻게 해야할까? 이 때 필요한 것이 바로 JSON.stringify
이다.
JSON.stringify
메서드는 객체를 JSON 포맷의 문자열로 변환시켜준다. 클라이언트가 서버로 객체를 전송하려면 객체를 문자열화해야 하기 때문이다.
이를 직렬화라고 부른다.
JSON.parse
메서드는 앞에 JSON.stringify메서드와 반대로 동작한다. JSON 포맷의 문자열을 객체로 변환시켜준다. 이를 역직렬화라고 한다.
자바스크립트가 Ajax를 통하여 XMLHttpRequeset 객체를 생성하고 어떻게 HTTP 요청을 하는지에 대한 순서는 아래와 같다.
HTTP에 대한 자세한 사항은 필자가 작성한 다음 포스팅을 참고하기 바란다.
http 대신 https를 적용해보자.
open 메서드는 서버에 전송할 HTTP 요청을 초기화하는 메서드이다. open 메서드를 호출하는 방법과 인수로 넣어주어야 하는 파라미터의 의미는 다음과 같다.
HTTP(하이퍼텍스트 전송 프로토콜)란 인터넷에서 데이터를 전송하는 데 사용되는 프로토콜 중 하나로, 웹 브라우저와 웹 서버 간의 통신을 위한 일종의 규약이다. 앞서 다룬 open 메서드, HTTP 요청 메서드 또한 클라이언트가 서버에게 요청할 데이터의 종류와 목적을 알리는 방법이다. 주로 5가지 요청 메서드를 사용하여 다음 그림과 같은 CRUD를 구현한다.
send 메서드는 open 메서드로 초기화된 HTTP 요청을 본격적으로 서버에 전송시켜준다. 기본적으로 서버로 전송하는 데이터는 GET, POST 요청 메서드에 따라 전송 방식에 차이가 있다.
페이로드란?
페이로드란 데이터 전송에서 전송된 실제 데이터를 의미한다. 일반적으로 JSON, XML, HTML과 같은 데이터 포맷이다.
send 메서드는 요청 몸체에 담아 전송할 데이터를 인수로 전달 할 수 있다. 페이로드가 객체인 경우 앞서 배웠듯이 JSON.stringify 메서드를 통해 반드시 직렬화(문자열로 변환) 한 다음 전달시켜주어야 한다.
setRequestHeader 메서드는 특정 HTTP 요청의 헤더 값을 설정한다. setRequestHeader 메서든느 반드시 open 메서드를 호출한 이후에 호출해야 한다. 자주 사용하는 HTTP 요청 헤더인 Content-type
과 Accept
에 대해 살펴보겠다.
HTTP 요청 헤드란?
HTTP 요청 헤더는 HTML의 head 태그처럼 클라이언트가 서버로 전송하는 메타데이터 정보를 담고 있다. 요청의 세부 정보를 포함한다.
Content-type
은 요청 몸체에 담아 전송할 데이터의 MIME 타입의 정보를 표현한다. 자주 사용 되는 MIME 타입은 다음과 같다.
아래는 Content-type
를 작성하는 코드 예시이다.
HTTP 클라이언트가 서버에 요청할 때 서버가 응답할 데이터의 MIME 타입을 Accept로 지정할 수 있는데 다음은 그 예시이다.
xhr.setRequestHeader('accept', 'application/json');
만약 Accept 헤더를 설정하지 않으면 send 메서드가 호출될 때 Accept 헤더가 */*
으로 전송된다.
서버가 전송한 응답을 처리할려면 XMLHttpRequest 객체가 발생시키는 이벤트 또한 캐치할 수 있어야 한다. 다양한 프로퍼티나 메서드를 제공하는 XMLHttpRequest 객체는 onreadystatechange
, onload
, onerror
와 같은 이벤트 핸들러 프로퍼티 또한 갖고있기 때문이다.
HTTP 요청을 전송하고 응답을 받을려면 당연히 서버가 필요하다. 다음 코드 예제는 JSONPlaceholder 에서 제공하는 가상 REST API를 사용한다.
//XMLHttpRequest 객체 생성
const xhr = new XMLHttpRequest();
//HTTP 요청 초기화
xhr.open('GET', 'https:~~~~');
//HTTP 요청 전송
xhr.send();
//readystatechange 이벤트는 HTTP 요청의 현재 상태를 나타내는 readyState 프로퍼티가 변경될 때마다 발생한다.
xhr.onreadystatechange = () => {
//readyState 프로퍼티는 HTTP 요청의 현재 상태를 나타낸다.
//readyState 프로퍼티 값이 4(XMLHttpRequest.DONE)가 아니면 서버 응답이 완료되지 않은 상태이다.
//만약 서버 응답이 완료되지 않을 경우 아무런 처리를 하지 않는다.
if( xhr.readyState !== XMLHttpRequest.DONE) return;
//status 프로퍼티는 응답 상태 코드를 나타낸다.
//status 프로퍼티 값이 200이면 정상적으로 응답이 되었다는 신호이다.
//status 프로퍼티 값이 200이 아니면 에러를 발생시킨다.
//정상적으로 응답이 되었을 때에만 reponse 프로퍼티에 서버의 응답 결과를 담는다.
if( xhr.status === 200 ) {
console.log(JSON.parse(xhr.response));
} else {
console.error('Error', xhr.status, xhr,statusText);
}
};