Ajax(Asynchronous JavaScript and XML)는 웹 페이지에서 비동기적으로 데이터를 요청하고 응답을 받기 위해 사용되는 기술들의 조합을 말합니다.
이를 통해 브라우저에서는 비동기적으로 데이터의 요청과 응답이 가능하며 동적인 웹을 만들기 위해 사용됩니다.
Ajax의 풀네임을 보면 JS를 이용해 XML파일만을 주고받을 수 있을 것 같은 이름이지만 실제로는 HTML, 텍스트 파일, 오디오 등 다양한 포멧을 지원하며 대부분 JSON형태를 주로 사용합니다.
초기의 Ajax는 데이터 통신을 위해서 오늘 다룰 XHR(XMLHttpRequest)객체를 주로 사용하였으나
현재는 XHR객체보다 Fetch API나 Axios와 같은 라이브러리를 많이 사용합니다.
그럼 본격적으로 시작하기 전에 위에서 말한 비동기와 동적 웹에 대해서 먼저 간단하게 알아보겠습니다.
동기와 비동기의 차이는 여러개의 작업을 어떤 방식으로 진행하는지입니다.
이해를 돕기위해 아래의 그림을 바탕으로 예를 들어보겠습니다.
우리가 만약 4개의 작업을 수행해야 하고 각 작업들은 도형에 있는 숫자만큼의 시간이 소요된다고 했을 때
동기방식으로 진행한다면 각 작업이 순서대로 진행되며 이전의 작업이 끝나야만 다음 작업을 수행합니다. 따라서 4개의 작업을 수행했을 때 총 28초가 소요됩니다.
반면 비동기방식은 여러 작업들을 동시다발적으로 실행시키기 때문에 여러개의 작업을 거의 동시에 진행합니다.
따라서 위의 예에서는 작업시간이 가장 오래 걸리는 10초가 총 작업시간이 되며 비동기 방식은 여러개의 작업을 처리해야할 때 동기 방식에 비해 더 빠르게 작업을 끝낼 수 있다는 장점이 있습니다.
정적 웹이란 HTML이 작성되어진 그대로만 보여지는 웹사이트를 말합니다.
회사소개나 약관처럼 모든 사용자에게 동일한 데이터를 보여줄 목적을 가진 페이지에 적합하며
만약 정적 웹에서 페이지의 내용 일부를 변경하고자 한다면 HTML 파일 자체를 변경해주어야 합니다.
또한 응답 데이터를 페이지에 반영하고자 한다면 서버에서 해당 데이터를 적용한 HTML을 다시 클라이언트에게 보내줘야 하는데 이는 일부 데이터 변경임에도 HTML전체를 다시 주고받아야하기 때문에 불필요하게 과도한 데이터 비용을 유발합니다.
반면 동적 웹은 HTML로 전체적인 부분을 만들어놓고 필요에 따라 JS로 DOM을 조작하여 사용자의 정보나 알맞는 데이터가 표시되야 하는 일부분만 수정하면 되기 때문에 정적 웹에 비해서 훨씬 적은 데이터 비용으로 유동적인 웹을 보여줄 수 있습니다.
만약 정적 웹으로 동적 웹처럼 사용자에 맞는 정보를 보여주고자 한다면 사용자 수 이상의 HTML파일이 필요합니다.
만약 유저가 로그인했을 때 유저의 ID를 페이지 일부분에 보여주는 웹사이트를 만들고 싶다면 초기 페이지 1개와 유저 100명의 ID가 적용된 페이지 100개 총 최소 101개의 HTML파일이 필요합니다.
하지만 이를 동적 웹으로 구현하면 최소 1개내지 2개의 HTML파일로 똑같이 구현할 수 있기 때문에 개발 및 수정도 쉽고 불필요한 데이터 비용도 줄일 수 있습니다.
동적웹은 유튜브, 페이스북, 네이버처럼 우리가 많이 사용하는 대부분의 페이지가 해당되며
정적웹은 회사소개 페이지, 약관처럼 모든 사용자에게 일관적으로 보여져도 상관이 없는 일부 페이지에만 적용됩니다.
XHR객체가 만들어지기 전인 IE6까지는 비동기를 위해 ActiveXObject(=XMLHTTP)라는 객체를 사용하였고
비동기가 없던 시절에는 오로지 정적으로만 데이터 요청이 가능했습니다.
Web API중 하나인 이 XHR 객체는 비동기적으로 서버와 통신할 수 있도록 해주는 Ajax의 핵심 역할을 하며
사용방법은 아래와 같습니다.
객체 생성 -> 상태가 변할때 호출 할 함수 설정 -> 객체 초기화 -> 요청보내기의 순서로
코드를 작성합니다.
XHR객체 생성은 전역 범위에서 선언 할 경우 XHR객체를 사용하는 다른 함수들과 충돌할 수 있으므로 꼭 함수 내부에서 생성해주어야 합니다.
open 메소드의 경우에는 아래와 같이 3개의 인자를 받습니다.
open(method, url, async?)
첫번째 인자인 method는 GET, POST, PUT, DELETE와 같은 HTTP method를 말하며 일부 브라우저의 경우 소문자를 인식 못하는 경우도 있기 때문에 대문자로 적어주는게 좋습니다.
두번째 인자인 URL은 요청을 보낼 서버의 URL을 말하며
세번째의 async는 선택 옵션으로 요청을 동기 or 비동기로 보낼것인지 여부입니다.
기본값은 true로 명시하지 않으면 비동기로 처리되지만 만약 false를 입력해 동기적으로 요청 할 경우
send메소드가 실행되고나서 응답이 오기 전까지는 뒤에 이어지는 작업을 하지 않고 멈춰있게 됩니다.
저는 테스트용 API를 제공해주는 jsonplaceholder 라는 사이트를 이용해 간단하게 데이터를 가져오는 상황을 구현 해봤습니다.
이렇게 데이터를 비동기적으로 요청하는것이 가능하고 요청과 응답이 완료된 후의 XHR객체의 내부 모습은 위의 사진과 같습니다.
XHR객체에서 자주 사용되는 속성들 위주로만 간단히 설명해보겠습니다.
- readyState
XHR객체 속성 중 하나인 readyState
는 요청 상태에 대해 숫자로 구분한 것이며
이 숫자(상태)가 변경될때마다 onreadystatechange
메소드가 호출 됩니다.
중요한건 이 readyState
는 응답의 성공과 실패 여부는 상관없이 오로지 요청이 완료 됬는지만 판단하기 때문에 이 값만 기준으로 요청의 성공여부를 판단할 수는 없습니다.
값 | 상태 | 설명 |
---|---|---|
0 | UNSENT | XHR객체 생성, open메소드가 호출되기 전 상태 |
1 | OPENED | open 메소드가 호출된 상태 (요청 초기화) |
2 | HEADERS_RECEIVED | send메소드가 호출된 상태 |
3 | LOADING | 응답에 따른 데이터를 다운받고 있으며 일부 데이터를 보관하고 있는 상태 |
4 | DONE | 응답 완료 |
- status
응답에 관련된 HTTP 상태 코드가 여기 들어가게 됩니다.
위와 같은 화면을 한번 쯤 보셨을텐데 이 404가 페이지를 찾을 수 없다는 뜻을 가진 HTTP 상태 코드입니다.
보통 200번대는 성공, 4~500번대는 실패를 나타냅니다.
이 외에 다른 상태 코드들은 아래 링크 위키피디아에 상세히 설명되어있습니다.
- onreadystatechange
xhr.onreadystatechange = function () {
// Execution
}
위에서 설명한 readyState
의 값이 변경될 때마다 호출되며 응답이 완료된 후의 실행할 함수를 삽입합니다.
요청이 끝나기 전부터 계속 호출되기 때문에 보통 함수내에서 조건문으로 readyState
의 값과 status
의 값을 기준으로 성공여부를 판단하고 각각 4, 200번대일 때 실행하도록 함수를 작성합니다.
또는 onload
속성이나 load
이벤트를 사용 할 수도 있는데 이 둘은 요청과 응답이 성공적으로 끝났을 때만 호출됩니다.
const xhr = new XMLHttpRequest();
// onload property
xhr.onload = function() {
// Execution
}
// load event
xhr.addEventListener("load", function() {
// Execution
})
- response
response는 응답에 대한 데이터를 표시하고
responseText
는 응답을 텍스트로 변환한 값,
responseType
은 응답 데이터의 종류,
responseURL
은 응답을 보낸 URL
responseXML
은 HTML이나 XML같은 문서형식의 데이터를 받아올 때 사용합니다.
위의 예제에서는 GET메소드만을 이용해 데이터를 받아오는 부분만 구현해봤는데
이번에는 POST를 통해 서버로 데이터를 보내는 것도 한번 구현해보겠습니다.
POST 메소드의 경우 서버로 데이터를 전송하기 때문에 데이터의 형식을 알려줄 수 있는
Content-type을 요청 헤더에 명시해주어야 하며 서버로 보낼 데이터는 send
메소드의 인자로 넣어주면 됩니다.
데이터의 종류를 알려주는 Content-type속성은 xhr객체의 setRequestHeader('Content-type', 'value')
형태로 open과 send메소드 사이에 작성해주어야 하며 데이터의 종류에 따라 알맞는 값을 넣어주어야 합니다.
종류는 워낙 다양하기 때문에 몇 가지만 예를 들어보자면
xml파일인 경우 text/xml,
mp3파일의 경우 audio/mpeg,
많이 사용하는 form data의 경우에는 Application/x-www-form-urlencoded이나
multipart/formed-data를 값으로 넣어줍니다.
더 많은 MIME타입에 대해서는 아래 링크에 나와있습니다.
만약 타입을 명시하지 않을 경우 브라우저가 데이터를 통해 타입을 유추하여 임의로 보내게 되며
명시하더라도 브라우저가 MIME 스니핑을 통해 데이터를 분석한 후 명시된 Content-type이 맞지 않다고 판단되면 브라우저에 의해 임의로 변경될 수 있습니다.
다음 시간에는 XHR객체를 대체하여 사용되는 Fetch API와 Axios에 대해 다뤄보겠습니다.