18.11 Ajax
Ajax
는 원래 비동기적 자바스크립트와 XML의 약어입니다.
Ajax
를 통해 서버와 비동기적으로 통신하면 페이지 전체를 새로 고칠 필요 없이 서버에서 데이터를 받아올 수 있습니다.
이 혁명적인 시스템은 2000년 초반 XMLHttpRequest
의 도입으로 가능해졌고, 웹 2.0이라 불리기도 했습니다.
Ajax
의 핵심 개념은 간단합니다.
브라우저 자바스크립트에서 HTTP 요청을 만들어 서버에 보내고 데이터를 받습니다.
받는 데이터는 보통 JSON 형식입니다.
XML로 받을 수도 있지만 JSON이 자바스크립트로 처리하기 훨씬 쉽습니다.
그리고 브라우저에서 그 데이터를 사용합니다.
Ajax
역시 다른 웹 페이지와 마찬가지로 HTTP 위에서 동작하지만, 페이지를 불러오고 렌더링하는 부담이 줄어들므로 웹 애플리케이션이 훨씬 빨라집니다(최소한 사용자는 훨씬 빠르다고 느낍니다).
Ajax
를 사용하려면 서버가 필요합니다.
20장에서 노드.js에 대해 설명하지만, 여기서는 노드.js로 아주 단순한 서버를 만들어 Ajax
서비스를 제공하겠습니다.
다음과 같이 Server.js 파일을 만드십시오.
const http = require('http');
const server = http.createServer(function (req, res) {
res.setHeader('Content-Type', 'application/json');
res.setHeader('Access-Control-Allow-Origin', '*');
res.end(JSON.stringify({
platform: process.platform,
nodeVersion: process.version,
uptime: Math.round(process.uptime()),
}))
});
const port = 7070;
server.listen(port, function () {
console.log(`Ajax server started on port ${port}`);
})
이 코드는 운영체제와 노드.js 버전, 서버 운영시간을 보고하는 매우 단순한 서버를 만듭니다.
NOTE_
Ajax
가 널리 쓰이면서 교차 소스 지원 공유(CORS)라는 잠재적 취약점이 드러났습니다.
이 예제에서는 Access-Control-Allow-Origin 헤더에*
값을 써서, 클라이언트(브라우저)가 보안 경고를 출력하지 않도록 했습니다.
실무 서버에서는 이렇게 하면 안 되고 기본적으로 허용되는 같은 프로토콜, 도메인, 포트를 사용하거나
서비스에 접속할 수 있는 프로토콜, 도메인, 포트를 명시해야 합니다.
예제로 사용할 때는 이렇게CORS
체크를 비활성화해도 안전합니다.
이 서버를 시작하려면 다음과 같이 입력하면 됩니다.
node Server
브라우저에서 http://localhost:7070에 방문하면 서버가 출력하는 결과를 볼 수 있습니다.
이제 서버가 생겼으니 샘플 HTML 페이지에서 Ajax 코드를 사용할 수 있습니다.
샘플 페이지는 이 장에서 쓰던 것을 그대로 쓰면 됩니다.
문서 바디에 Ajax
로 받아올 정보를 표시할 플레이스홀더부터 만듭시다.
<div class="serverInfo">
Server is running on <span data-replace="platform">???</span>
with Node <span data-replace="nodeVersion">???</span>. It has
been up for <span data-replace="uptime">???</span> seconds.
</div>
서버에서 가져온 정보를 표시할 곳을 만들었으니 XMLHttpRequest
를 써서 Ajax
호출을 보낼 수 있습니다.
HTML 파일 마지막, </body>
태그의 바로 앞에 다음 스크립트를 추가하십시오.
function refreshServerInfo() {
const req = new XMLHttpRequest();
req.addEventListener('load', function() {
// TODO: 값을 HTML에 삽입하는 것은 나중에 합니다.
console.log(this.responseText)
});
req.open('GET', 'http://localhost:7070', true);
req.send();
}
refreshServerInfo();
이 스크립트는 기본적인 Ajax
호출을 보냅니다.
먼저 XMLHttpRequest
객체를 만들고, Ajax
호출이 성공했을 때 발생한 load 이벤트에 대한 이벤트 리스너를 만들었습니다.
지금은 서버 응답인 this.responseText
를 콘솔에 출력하기만 하면 됩니다.
다음에는 open
을 호출해 서버에 실제 연결합니다.
이 함수에서는 브라우저에서 웹 페이지에 방문할 때 사용하는 것과 같은 HTTP GET
요청을 쓴다고 명시하고, 서버 URL을 넘겼습니다.
마지막으로 send
를 호출해 요청을 실행했습니다.
이 예제에서는 서버에 아무 데이터도 보내지 않았지만 원한다면 보낼 수 있습니다.
예제를 실행하면 서버에서 반환한 데이터가 콘솔에 기록됩니다.
다음 단계는 이 데이터를 HTML에 삽입하는 겁니다.
HTML을 만들 때 데이터 속성 replace
가 있는 요소만 찾고, 그 요소의 콘텐츠를 반환받은 객체에서 뽑아낸 데이터로 교체할 수 있게 만들었습니다.
서버에서 반환한 객체의 프로퍼티를 Object.keys
를 통해 순회하고, replace
데이터 속성이 일치하는 요소가 있으면 그 콘텐츠를 교체하면 됩니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Event Propagation</title>
</head>
<body>
<div class="serverInfo">
Server is running on <span data-replace="platform">???</span>
with Node <span data-replace="nodeVersion">???</span>. It has
been up for <span data-replace="uptime">???</span> seconds.
</div>
<script>
function refreshServerInfo() {
const req = new XMLHttpRequest();
req.addEventListener('load', function() {
// TODO: 값을 HTML에 삽입하는 것은 나중에 합니다.
console.log(this.responseText)
});
req.open('GET', 'http://localhost:7070', true);
req.send();
req.addEventListener('load', function () {
// this.responseText는 JSON이 들어있는 문자열입니다.
// JSON.parse를 써서 문자열을 객체로 바꿉니다.
const data = JSON.parse(this.responseText);
// 이 예제에서는 클래스가 serverInfo인 div 의 텍스트만 교체합니다.
const serverInfo = document.querySelector('.serverInfo');
// 서버에서 반환한 객체를 키 기준으로 순회합니다.
Object.keys(data).forEach(p => {
// 텍스트를 교체할 요소를 찾습니다.
const replacements = serverInfo.querySelectorAll(`[data-replace="${p}"]`);
// 서버에서 받은 값으로 텍스트를 교체합니다.
for (let r of replacements) {
r.textContent = data[p];
}
})
})
}
refreshServerInfo();
</script>
</body>
</html>
refreshServerInfo
는 함수이므로 언제든 호출할 수 있습니다.
uptime
필드는 서버가 얼마나 오래 열려 있었는지 나타내므로, 이런 정보는 주기적으로 업데이트해야 할 수 있습니다.
예를 들어 초당 다섯 번, 그러니까 200 밀리초마다 서버에서 정보를 새로 받아오려면 다음과 같이 합니다.
setInterval(refreshServerInfo, 200);
이렇게 하면 브라우저에서 서버 운영시간이 실시간으로 갱신됩니다.
NOTE_
이 예제에서는 페이지를 처음 불러올 때<div class="serverInfo">
안에 플레이스홀더 구실을 하는 물음표가 들어 있습니다.
사용자의 인터넷 연결이 느리다면 서버에서 받아온 정보가 교체하기 전에 물음표가 잠시 보일 수 있습니다.
이런 문제를 FOUC(flash of unstyled content)라고 부르며, 이 외에도 몇 가지 종류가 있습니다.
가장 좋은 해결책은 서버에서 각 필드의 초깃값을 처음부터 만들어 보내는 겁니다.
콘텐츠 업데이트가 끝나기 전에는 요소 전체를 숨기는 방법도 있습니다.
이렇게 해도 약간의 거슬림을 막을 수는 없지만, 무의미한 물음표가 표시되는 것보다는 낫습니다.
이 장에서는 Ajax 요청에 관한 기본적인 개념만 설명했습니다.
더 자세히 배우고 싶다면 MDN에서 XMLHttpRequest
를 설명한 문서를 보십시오.