Ajax를 사용하기 전의 웹이란?
Ajax가 등장하기 전에는 웹 브라우저가 데이터를 요청하면 서버는 해당 정보를 "통째"로 보내주게 되었었다.
과거에는 사실 이게 큰 문제가 되지 않았는데 현재 사정과는 어느정도 맞지 않는 부분들이 많다.
가령 아래와 같은 예시를 보도록 하자.
위의 프로젝트는 과거 필자가 만들었던 채팅프로그램이다.
왼쪽과 오른쪽은 레이아웃이 거의 같다. 특히 좌측 네비게이션과 헤더는 아예 동일한 소스를 쓰고 있다.
그럼에도 불구하고 새로운 url을 호출할때 마다 모든 페이지를 새로그려야한다.
이러한 방식은 서버에도, 클라이언트에도 안좋은 영향을 미칠 확률이 높다고 할 수 있다.
물론 페이지의 변환이 적다면 상관없겠지만 페이지가 민감하게 변해야한다면 이는 매우 큰 손해로 다가올 것이다.
그래서 우리는 "비동기"적으로 정보를 요청하는 새로운 기술이 필요했다.
이미 페이지를 렌더링하고 나서도 경우에 따라서 데이터를 받아오는 것이다.
만약 특정부분만 데이터를 가져와서 변경할 수 있다면 서버는 서버대로 데이터를 필요한 양만큼보내서 좋다.
클라이언트는 클라이언트대로 적은 데이터를 렌더링하므로 부하가 적게걸리게된다.
Asynchronous JavaScript and XML
그리하여 마들어진게 바로 Ajax이다. Ajax는 위의 약자인데 다시 정리해서 말하자면,
비동기적으로 JavaScript와 XML을 이용하는 방식이라고 할 수 있다.
물론...
실제로는 XML은 Ajax에서 잘 쓰이지 않게 됬는데 데이터 전송의 흐름이 XML에서 Json으로 넘어왔기 때문이다.
사실 잘 쓰이지 않는 정도가 아니라 필자는 본적도 없다. 물론 그렇게 쓰는 사람이 존재는 하겠지.
뭔가 붕어빵에 붕어가 안들어간것 마냥 위화감이 들지만 프로그래밍 세계에서는 이런일은 흔하다.
어쨋든 이 ajax를 사용하면 데이터를 비동기적으로 받는것이 가능해진다.
ajax를 무슨 기술인것 처럼 아는 사람들이 있던데 사실 기술은 아니고 정보 교환 기법중 하나이다.
따라서 javascript구문내에서 xml을(json이나 다른 yaml, 심지어 text도 가능)이용해서 비동기를 사용하기만 하면된다.
그래서 여러가지 서브파티 라이브러리들이 존재한다.
그러나 이 모든 서브파티 라이브러리들도 깊게 들어가면 딱 한가지의 방식을 사용하는걸 알 수 있다.
그 태초적인 방식이 바로 XMLHttpRequest이다.
XMLHttpRequest
여러분은 복잡한 서브파티라이브러리를 사용할 필요가 없다.
아... 복잡하다는 말은 어폐가 있겠다. 왜냐하면 서브파티들이 훨씬 간단하니까.
그리고 이러한것들이 사실 XMLHttpRequest보다 훨씬 사용하기 간편하면 promise로 포팅된 다양한 라이브러리가 있다.
그래서 그걸 배우고 나면 사실 이를 건드릴 이유는 없다.
그럼에도 불구하고 이게 제일 먼자 나오는것은 사실 모든 라이브러리들이 XMLHttpRequest를 모체로 하고 있기 때문이다.
그럼시작하기에 앞서서 예제를 보도록하자.
API 문서 : https://webplatform.github.io/docs/apis/xhr/XMLHttpRequest/
서버 소스 : https://github.com/justkukaro/REST-Test-Server
서버는 간단하게 nodejs express로 ejs템플릿을 사용해서 만들었다.
만약 마음에 안든다면 여러분이 만드셔도 무방하다.
서버의 역활은 단순히 json데이터 하나 날리는게 끝이다. 그러므로 서버를 따로 설명하진 않겠다.
이제 클라이언트쪽 소스를 보도록하자.
<!DOCTYPE html>
<html lang="kr">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === xhr.DONE) {
if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText);
} else {
console.error(xhr.responseText);
}
}
};
xhr.open('GET', 'http://localhost:3000/single-json');
xhr.send();
</script>
</body>
</html>
가장 기초적인 코드이다.
위 코드를 하나하나 해석해보도록 하자.
var xhr = new XMLHttpRequest();
당연히 생성자 호출이다. 말할것도 없다.
xhr.onreadystatechange = function() {
if (xhr.readyState === xhr.DONE) {
if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText);
} else {
console.error(xhr.responseText);
}
}
};
이 부분은 이벤트 콜백을 붙히는 부분이다. 자세한건 API문서를 참조하면되지만 간단한건 알려드리곘다.
먼저 onreadystatechange는 이벤트중 하나이다. 영어그대로 준비상태가 바뀌었는지를 확인하는 것이다.
우리는 준비상태가 변경되었을 경우 이벤트를 콜백하겠다는 의미이다.
더쉽게 말하면 XMLHttpRequest의 신변에 무슨일이 생기면 발동하겠다는 뜻이다.
그럼 readyState를 본다. readyState는 여러종류가 있는데 그 중에서 DONE은 요청이 정상적으로 도달해서 끝났음을 의미한다.
그 다음 상태코드를 봐서 200이나 201일경우 log를 실행, 실패했을 경우 error를 실행한다.
xhr.open('GET', 'http://localhost:3000/single-json');
xhr.send();
말 그대로 open은 보내는 스트림을 여는것을 의미하고 send는 보내는 것을 의미한다. 이까지보면 매우 쉽다.
서버가 제대로 열려 있다면 아래와 같이 뜰 것이다.
클라이언트에 데이터가 도달한 것을 확인할 수 있다.
또한 서버에서도 접속된걸 확인할 수 있다.
만약에 도중에 급하게 요청을 취소하려고 한다면 아래와 같이 코드를 작성하면된다.
xhr.abort();
이 코드는 보내고 받는 루틴자체를 멈춰버리는 효과가 있다. 즉 정지버튼누른것과 같은 효과이다.
그럼 request에 body를 주고싶다면 어떻게 해야할까?
그 방법은 아래와 같다.
<!DOCTYPE html>
<html lang="kr">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
var xhr = new XMLHttpRequest();
var formData = {'age': 26, 'lang': 'JS', 'drink': 'zero coke'};
xhr.onreadystatechange = function () {
if (xhr.readyState === xhr.DONE) {
if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText);
} else {
console.error(xhr.responseText);
}
}
};
xhr.open('POST', 'http://localhost:3000/single-json');
xhr.setRequestHeader('Content-type', 'application/json');
xhr.send(JSON.stringify(formData));
</script>
</body>
</html>
코드의 전문이다.
새로 추가된 코드들만 보도록 하자.
var formData = {'age': 26, 'lang': 'JS', 'drink': 'zero coke'};
일단 이는 날리고 싶은 데이터이다.
xhr.open('POST', 'http://localhost:3000/single-json');
xhr.setRequestHeader('Content-type', 'application/json');
그다음 open을 post로 열어준다.
그 다음 header를 선언한다. 반드시 열고나서 선언해야 의미가 있다.
우리는 json타입으로 보낼거기 때문에 json으로 선언했다.
만약 다른 타입을 하고싶으면 다른타입을 선언하고 그에 맞게 데이터를 인코딩해주면된다.
xhr.send(JSON.stringify(formData));
데이터는 처리를 하지 않고 문자열로 raw하게 날라가므로 반드시 본인이 타입에 맞게 인코딩 해줘서 날려야한다.
이정도 예시면 충분하지만 form데이터 처럼 날리고 싶다면 아래를 참조하라.
<!DOCTYPE html>
<html lang="kr">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:3000/single-json" method="post">
<input type="text" name="test">
<input type="submit">
</form>
<script>
var xhr = new XMLHttpRequest();
var formData = {'age': 26, 'lang': 'JS', 'drink': 'zero coke'};
xhr.onreadystatechange = function () {
if (xhr.readyState === xhr.DONE) {
if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText);
} else {
console.error(xhr.responseText);
}
}
};
xhr.open('POST', 'http://localhost:3000/single-json');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(jsonConvert(formData));
function jsonConvert(jsonObject) {
var result = '';
var token = '';
Object.keys(jsonObject).map((key, idx) => {
if (idx === 1) {
token = '&';
}
result += `${token}${key}=${jsonObject[key]}`;
});
return result;
}
</script>
</body>
</html>
사실 위의 예제를 봤으면 알겠지만 위와 동일하므로 설명할건 딱 하나밖에 없다.
xhr.send(jsonConvert(formData));
post데이터를 form으로 날리면 application/x-www-form-urlencoded로 날라가게된다.
그러므로 우리도 헤더를 동일하게 설정해준다.
jsonConvert라는 함수는 존재하지 않으므로 우리가 만들어준다.
function jsonConvert(jsonObject) {
var result = '';
var token = '';
Object.keys(jsonObject).map((key, idx) => {
if (idx === 1) {
token = '&';
}
result += `${token}${key}=${jsonObject[key]}`;
});
return result;
}
이 함수는 json데이터를 마치 form데이터로 인코딩 해주는 코드이다.
이제 날려보면 답을 확인해 볼 수 있다.
이렇게 비동기로 통신해서 사용할 수 있는 가장 기초적인 방법을 알아보았다.
더 자세한 설명을 보고싶다면 docs를 확인해보라.
이까지만 봐도 여러분은 이미 ajax에 대해서 많은 얻었지만 사실 여러가지 방법이 혼재한다.
다음 포스팅에서는 거기에 대해서 논해보도록 하자.