안녕하세요. 이번 시간에는 AJAX 요청을 보내는 대표적인 방법인 XMLHttpRequest(XHR) 사용 방법에 대해서 알아보겠습니다. 다른 웹사이트나 블로그에서 AJAX 코드를 많이 보셨을텐데요. 제가 자세히 설명드리고, 2017년에 맞는 방법으로 다시 알려드리겠습니다.
보통 코딩이 두려워서 jQuery AJAX를 많이 쓰실텐데요. 어렵지 않습니다. 여러분도 이제 XHR를 사용하실 수 있게 될 겁니다.
지난 시간의 FormData 객체는 꼭 기억해두세요. FormData 객체에 담긴 파일을 AJAX로 서버에 보낼 겁니다. 그리고 이 강좌는 Node.js의 이미지 업로드 강좌 와 이어집니다.
먼저 AJAX 요청을 보내는 XMLHttpRequest 객체를 생성해줍니다. 이 객체는 window 객체 아래에 위치합니다. 간단하게 아래와 같이 사용하시면 됩니다.
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', 'https://www.zerocho.com/api/get'); // 메소드와 주소 설정
xhr.send(); // 요청 전송
// xhr.abort(); // 전송된 요청 취소
혹시 다른 사이트에서 ActiveXObject를 보신 분도 있을 겁니다. IE7 이상부터는 필요 없습니다. 설마 아직도 IE6을 지원하는 곳은 없겠죠?
xhr 객체를 만든 후 open 메소드로 요청을 열고 주소와 HTTP 메소드를 설정한 뒤, send 메소드로 요청을 서버로 보냅니다. GET 외에도 POST, PUT, PATCH, DELETE, HEAD 등의 메소드를 설정하시면 됩니다.
onreadystatechange가 요청에 대한 응답을 받는 이벤트 리스너인데요. 먼저 readyState에 대해서 아셔야 합니다. AJAX 요청 시 XHR 객체는 각 상태별로 readyState가 바뀝니다. 처음에는 readyState가 0(xhr.UNSENT
, 보내지 않음)이었다가, open 메소드를 호출하는 순간 1(xhr.OPENED
)로 바뀝니다. 그리고 send 시 순차적으로 2(xhr.HEADERS_RECEIVED
), 3(xhr.LOADING
), 4(xhr.DONE
)로 바뀝니다.
readyState가 바뀔 때마다 onreadystatechange에 설정해두었던 콜백 함수가 호출됩니다. 최종적으로 readyState가 4(xhr.DONE
)가 되었을 때 요청이 완료가 된 것이기 때문에 이제 xhr.status
로 HTTP 상태 코드를 확인하고요. 상태 코드가 성공을 가리키는 200이나 201일 때 응답을 확인합니다. 아니면 에러를 표시합니다. readyState가 바뀌는 것은 onreadystatechange 안에 다음 코드를 추가하면 실시간으로 확인하실 수 있습니다.
if (xhr.readyState === xhr.UNSENT) {
console.log('unsent');
}
if (xhr.readyState === xhr.OPENED) {
console.log('opened');
}
if (xhr.readyState === xhr.HEADERS_RECEIVED) {
console.log('headers received');
}
if (xhr.readyState === xhr.LOADING) {
console.log('loading');
}
onreadystatechange 대신에 onload를 사용해도 됩니다. 요청 완료만 잡아내도 된다면요. 이외에도 onprogress, onerror, onabort 등이 있습니다만 그리 자주 쓰이지는 않습니다. 아래 예시부터는 onload를 사용하겠습니다. 가장 먼저 GET 메소드일 때 XHR로 요청을 보내보겠습니다. GET 요청은 HTTP 스펙 상 body에 데이터를 보내면 안 됩니다. 데이터를 굳이 보내고 싶다면 주소에 쿼리스트링을 붙여 보내시면 됩니다.
var xhr = new XMLHttpRequest();
xhr.onload = function() {
if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText);
} else {
console.error(xhr.responseText);
}
};
xhr.open('GET', 'https://www.zerocho.com/api/get?name=zerocho');
xhr.send();
이번에는 POST 요청을 보내봅시다. 주로 JSON을 보내거나 FormData를 body에 실어 보냅니다. 먼저 JSON을 보내보겠습니다.
var xhr = new XMLHttpRequest();
var data = {
name: 'zerocho',
birth: 1994,
};
xhr.onload = function() {
if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText);
} else {
console.error(xhr.responseText);
}
};
xhr.open('POST', 'https://www.zerocho.com/api/post/json');
xhr.setRequestHeader('Content-Type', 'application/json'); // 컨텐츠타입을 json으로
xhr.send(JSON.stringify(data)); // 데이터를 stringify해서 보냄
네. 거의 비슷한데 setRequestHeader 메소드로 보내는 데이터가 JSON이라는 것을 알리고, send 메소드에 데이터를 stringify해서 보내면 됩니다. 폼 데이터는 아래와 같이 보냅니다.
var xhr = new XMLHttpRequest();
var formData = new FormData();
formData.append('name', 'zerocho');
formData.append('birth', 1994);
xhr.onload = function() {
if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText);
} else {
console.error(xhr.responseText);
}
};
xhr.open('POST', 'https://www.zerocho.com/api/post/formdata');
xhr.send(formData); // 폼 데이터 객체 전송
별도로 header 설정을 할 필요 없이 그냥 formData를 보내주면 됩니다. 더 간단하죠? 자동으로 Content-type이 multipart/form-data가 됩니다. 이미지나 파일도 저렇게 formData에 넣어서 보내주면 됩니다.
구형 IE가 판을 치던 시절에는 AJAX 요청을 보내기가 까다로워 jquery AJAX나 axios, superagent같은 라이브러리를 많이 사용했는데요. 모던 브라우저들이 나오면서 위와 같이 직접 XHR을 다뤄도 될 정도로 깔끔해졌습니다. 물론 지금도 여러 가지 예외사항 때문에 라이브러리를 사용하는 것을 더 추천합니다.
XHR 또한 복잡하다는 의견이 많아 Fetch API가 등장했습니다. IE에서는 사용할 수 없지만 최신 브라우저에서는 다 사용가능한 API입니다. 모바일 iOS에서도 안 됐었는데 2017년부로 사용가능해졌습니다. 야호! 포스팅이 길어져서 다음시간에 알아봅시다.