Ajax란?
Ajax는 Asynchronous JavaScript And XML의 약자로, XMLHttpRequest 객체를 이용하여 비동기 방식으로 서버와 통신을 하는 것을 말한다. 웹 브라우저의 클라이언트와 서버간 통신은 url를 이용한 http 통신으로 이루어진다. 즉 브라우저가 서버로 request를 날리기 위해서는 해당 브라우저의 url 주소를 변경하여야 하는데 이때는 페이지 이동이 일어나게 된다. 하지만 ajax 의 경우 브라우저의 url 주소의 변경을 이용하지 않고 내부적으로 통신하여 response 를 받아오기 때문에 특정 데이터만 불러오거나 비동기로 데이터를 불러와야하는 경우 사용된다. 이때 Same Origin Policy 정책으로 인해 cross domain 을 허용하지 않기 때문에 외부 도메인을 사용하여야 하는경우 JSONP, XML 등을 이용하여야 한다.
비동기적이란, 서버에 요청을 하고 그냥 기다리는 것이 아닌, 기다림과 동시에 다른 작업을 할 수 있다는 것을 말한다. Ajax가 가지고 있는 중요 특징은 바로 이 비동기성으로, 서버로부터 웹페이지가 반환될 때, 화면 전체를 갱신하지 않고, 페이지 일부만을 갱신하게 해준다. 즉, 페이지 이동이나 새로고침 없이 페이지 일부만을 갱신할 수 있다. 예를 들어, 사용자가 페이지에서 어떤 이벤트를 발생시키면, 페이지 전체가 아닌 페이지 일부분만을 업데이트해서 보여주기 때문에, 페이지 전체가 Refresh 되지 않아, 사용자가 그 일부의 데이터를 기다리면서, 다른 일을 하여도 문제가 없다.
Ajax를 사용하는 대표적인 애플리케이션이 페이스북 타임라인이다. 페이스북 타임라인을 밑으로 내려가면서 보면, 그 페이스북 페이지 자체는 그대로 있는데, 필요한 타임라인 데이터만 받아올 수 있다. 웹 사이트 중 페이지 전환없이 새로운 데이터를 불러오는 사이트는 대부분 Ajax 기술을 사용하고 있다.
JSON이란?
JSON은 JavaScript Object Notation의 약자로, 클라이언트와 서버간에 데이터를 교환하기 위해 필요한 데이터 포맷을 말한다. 예전에는 데이터 교환을 위한 데이터 포맷으로 XML을 사용했으나, 요즘에는 데이터 구조화도 잘 되어있고, 가볍고 가독성이 좋은 JSON을 사용한다. JSON의 형태는 자바스크립트의 객체 리터럴과 비슷하지만, 순수 문자열로 구성된 규칙이 있는 구조화된 데이터 포맷이다.
1 | { |
JSON의 이름(key)는 반드시 큰따옴표(“”)로 둘러싸야 한다.(작은따옴표(‘’)는 사용이 안된다.)
JSON.parse() & JSON.stringify()
클라이언트와 서버간에 통신을 할때는, JSON 형태, 즉 문자열로 데이터를 주고 받는다. 그러나, 서버로부터 응답받은 데이터를 클라이언트(브라우저)에서 사용하기 위해서는 JSON 형태의 문자열을 객체로 바꿔줘야 한다. 이를 역직렬화(Deserializing)이라고 하는데, 이를 위해서는 내장 객체 JSON의 static 메소드인 JSON.parse()를 사용해야 한다.
이와 반대로, 클라이언트(브라우저)에서 서버로 데이터를 보내기 위해서는 객체를 문자열로 바꿔줘야 한다. 이때는 JSON.stringify()를 사용해야 한다.
JSON.stringify()에 대해 자세히 확인해보자.
Ajax Request & Response
Javascript를 이용해서 서버로 보내는 Ajax Request를 만들기 위해서는 XMLHttpRequest 객체를 사용해서 Ajax 요청을 생성하고 전송한다. 서버로부터 응답을 받을때도 XMLHttpRequest 객체를 사용해서 처리한다. 즉, XMLHttpRequest 객체의 프로퍼티 및 메소드를 사용하여 코드를 작성한다.
코드 작성시, 크게 3가지로 나눌 수 있다.
- 서버로 요청 보내기
- 서버로 요청보낼때, Request Header 보내기
- 서버로부터 받은 응답 처리하기
1. Ajax Request 보내기
XMLHttpRequest 객체를 사용해서 Ajax 요청 처리에 대한 코드는 다음과 같다.
1 | var xhr = new XMLHttpRequest(); |
1-1. XMLHttpRequest 인스턴스 생성
1 | // XMLHttpRequest 생성자로 xhr 인스턴스를 생성 |
XMLHttpRequest 객체는 다양한 프로퍼티 및 메소드를 가지고 있다.
1-2. XMLHttpRequest.open()으로 요청 준비
1 | // XMLHttpRequest가 가지고 있는 open 메소드로 요청을 준비 |
XMLHttpRequest.open 메소드를 사용할 때, 인수는 다음과 같다.
- 첫번째 인수: HTTP Method(GET/POST/PUT/PATCH/DELETE 등)를 사용
- 두번째 인수: 요청 보낼 URL
- 세번째 인수(옵션): async로 비동기를 나타낸다.(true면 비동기, false면 동기인데, 아무것도 작성안하면 default로 비동기이다.)
1-3. XMLHttpRequest.send()로 요청 전송
1 | // XMLHttpRequest가 가지고 있는 send 메소드로 요청을 전송 |
서버에 요청을 준비하는 단계를 보자.1
xhr.open('GET', '/users');
이때 HTTP Method로 ‘GET’을 사용하게 되면, URL의 일부분인 query string(쿼리문자열)로 데이터를 서버로 전송하기 때문에, send 메소드에 인수로 데이터를 보낼 필요가 없다. send 메소드에 인수를 Request Body라고 하는데, 이부분이 null이 되어, 무시된다.
그럼 만약, ‘GET’이 아닌 ‘POST’를 하게되면 어떻게 될까?
2. 서버로 요청보낼때, Request Header 보내기
‘POST’의 경우, 데이터(payload)를 Request Body에 담아 전송한다.1
2
3
4xhr.send(({
name: "donald",
country: "United States"
}));
이럴 경우, XMLHttpRequest.setRequestHeader() 메소드를 사용해서, HTTP Request Header의 값을 설정해야 한다. 이때, setRequestHeader 메소드는 open 메소드 다음에, send 메소드 전에 호출해야 한다. 다음과 같이 작성하면 된다.1
2
3
4
5
6xhr.open('POST', '/users');
xhr.setRequestHeader('Content-type', 'application/json');
xhr.send({
name: "donald",
country: "United States"
});
setRequestHeader 메소드를 사용할 때, 인수는 다음과 같다.
- 첫번째 인수: 자주 사용하는 Request Header인 Content-type 또는 Accept을 사용한다.
- 두번째 인수: MIME 타입
예를 들어, 아래와 같은 코드를 보자.1
xhr.setRequestHeader('Content-type', 'application/json');
‘Content-type’은 Request Body에 담아 전송할 데이터의 MIME-type을 지정할 때 사용한다.
MIME-type은 아래 테이블에 있는 타입들이며, 사용시에는 아래 서브타입처럼 작성한다.
타입 | 서브타입 |
---|---|
text 타입 | text/plain, text/html, text/css, text/javascript |
Application 타입 | application/json, application/x-www-form-urlencode |
File 업로드하기 위한 타입 | multipart/formed-date |
Request Body에 담아 전송할 데이터의 MIME-type을 지정하는 예제 코드는 다음과 같다.1
2
3
4
5
6xhr.open('POST', '/users');
xhr.setRequestHeader('Content-type', 'application/json');
xhr.send(JSON.stringify({
name: "donald",
country: "United States"
});
‘Accept’은 HTTP 클라이언트가 서버에 요청할 때, 서버가 센드백할 데이터의 MIME-type을 지정할 때 사용한다.
예를 들어, 아래와 같이 작성한다.1
xhr.setRequestHeader('Accept', 'application/json');
만약 ‘Accept’ 헤더를 설정하지 않을 경우, send 메소드가 호출될 때, ‘Accept’ 헤더가 /와 함께 전송된다.
(/은 모든 MIME 타입을 의미한다.)
자세한 ‘Accept’에 대한 개념은 MDN에서 확인해보자.
클라이언트와 서버사이에서의 Request & Response Message는 다음과 같다.
출처: HTTP Request and Resopnse Message
3. 서버로부터 받은 응답 처리하기
XMLHttpRequest 객체를 사용해서 Ajax 응답 처리에 대한 코드는 다음과 같다.
1 | xhr.onreadystatechange = function (e) { |
3-1. XMLHttpRequest.onreadystatechange 호출
XMLHttpRequest가 가지고 있는 readyState 프로퍼티가 변경(사용자로부터 이벤트 발생) 될 때마다, XMLHttpRequest가 가지고 있는 프로퍼티인 onreadystatechange(이벤트 핸들러)를 호출한다.1
2
3xhr.onreadystatechange = function (e) {
// readyState 프로퍼티가 변경될 때마다, 이 함수를 호출
}
3-2. XMLHttpRequest.readyState로 서버가 응답했는지 확인
1 | if (xhr.readyState === XMLHttpRequest.DONE) { |
XMLHttpRequest.readyState의 값은 아래와 같다.
Value | State | Description |
---|---|---|
0 | UNSENT | XMLHttpRequest.open() 메소드 호출 이전 |
1 | OPENED | XMLHttpRequest.open() 메소드 호출 완료 |
2 | HEADERS_RECEIVED | XMLHttpRequest.send() 메소드 호출 완료 |
3 | LOADING | 서버 응답 중(XMLHttpRequest.responseText 미완성 상태) |
4 | DONE | 서버 응답 완료 |
xhr.readyState의 값이 4(DONE)이면, 서버가 응답을 완료했다는 뜻이다.
3-3. XMLHttpRequest.status로 정상 응답인지 확인
1 | if(xhr.status === 200) { |
응답코드가 200번 대 숫자면 정상 응답이므로, xhr.status가 정상적인 응답코드이면, 서버로부터 전송되는 데이터가 담겨 있는 xhr.responseText가 클라이언트로 전달된다.