게시글

5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭
강좌15 - HTML&DOM - 7년 전 등록

AJAX 요청

XMLHttpRequest

안녕하세요. 이번 시간에는 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년부로 사용가능해졌습니다. 야호! 포스팅이 길어져서 다음시간에 알아봅시다.

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.
5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭

댓글

7개의 댓글이 있습니다.
6년 전
해결했습니다! app.use(bodyParser.json()); 를 설정해놨어야 했네요.. 감사합니다~
6년 전
추가로 bodyParser.json이 express에 내장되어, express.json() 하셔도 됩니다.
6년 전
좋은 자료 정말 감사합니다. 실습중 어제부터 계속 막히는 부분이 있어서 질문 드립니다. JSON.stringify(data)를 POST방식으로 전송했고 전송한 데이터를 라우트 미들웨어(app.post)에서 req.body로 받으려고 했지만 계속 빈객체가 출력됩니다. 어디를 의심해 봐야 할까요? 물론 xhr.setRequestHeader('Content-Type', 'application/json')요것도 설정해놨습니다.. formData처럼 multer가 필요한 건가요? 다시 클라이언트로 전송할 데이터는 같은 미들웨어에서 res.redirect로 해주고 있는데 아주 잘 되고 있습니다. 클라이언트에서 받아오는게 안되네요..
6년 전
좋은 자료 정말 감사합니다. 실습중 어제부터 계속 막히는 부분이 있어서 질문 드립니다. JSON.stringify(data)를 POST방식으로 전송했고 전송한 데이터를 익스프레스의 라우트 미들웨어(app.post)에서 req.body로 받으려고 했지만 계속 빈객체가 출력됩니다. 어디를 의심해 봐야 할까요? 물론 xhr.setRequestHeader('Content-Type', 'application/json')요것도 설정해놨습니다..
6년 전
아 많은 도움이 됐습니다. 정말 자세한 설명 감사드려요
6년 전
궁금한게 있습니다 책엔 onload 여기선 onreadystatechange 를 쓰셨는데요 요청을 열어두고 요청을 보낸후에 왜 저 두가지 메소드가 작동하는지 모르겠으면 뭘 보면 되는지 알수 있을까요?? 제 생각엔 요청을 보내면 xhr객체의 프로퍼티인 readyState가 변경되서 이벤트가 일어나는건가 싶었는데 onload는 어떤것을 기준으로 되는지도 잘 모르겠어서요.. 부탁드립니다.
6년 전
onload는 readystate가 xhr.DONE일 때 같이 발생한다고 보시면 됩니다~
6년 전
안녕하세요 제로조님! 제로조님의 책을 보다가 문득 궁금한게 생겼는데
AJAX부분을 XML로 작성하신 이유가 궁금합니다.
6년 전
xhr말고 다른 옵션이 있나요?
6년 전
죄송합니다, 제가 아무것도 모르고 이상한 질문을 했네요. 제가 궁금했던 부분은 Nodejs교과서에 적혀있는 Ajax 스크립트를 이해하고 싶으면 어떻게 접근해야하는가 입니다. 제이쿼리나 라이브러리를 사용하기 전에 먼저 자바스크립트로만 쓰여진 제로조님의 스크립트를 이해하고 싶습니다.
6년 전
xmlhttprequest 객체에 대해 구글에 검색하시면 mdn 문서가 있습니다. 그 것을 읽어보시면 됩니다.
6년 전
감사합니다^^!
6년 전
그리고 책에보면 HTML코드 보다는 서버 코드 위주 보라고 적어놓으셨는데 이 서버 코드 위주라는게 script코드도 포함되나요?
6년 전
script는 포함되지 않습니다.
6년 전
정말 감사합니다^^
7년 전
fetch 강의도 올려주세요!
7년 전
내일 올리도록 하겠습니다!