Study/Javascript, Jquery, CSS

[Javascript] 비동기 통신(Ajax)를 하는 방법

v명월v 2020. 3. 31. 00:01

안녕하세요. 명월입니다.


이 글은 Javascript에서 비동기 통신(Ajax)를 하는 방법에 대한 글입니다.


먼저 Ajax(Asynchronous JavaScript And XML) 란 비동기 자바스크립트와 XML를 뜻하는 말로써, 웹 서버와 클라이언트 통신(웹 서버에 http protocal 형식으로 요청하면 http protocal 응답을 받는 형식)를 동기식(브라우저 화면에서 요청을 하고 결과를 기다리는 형태)가 아닌 백그라운드로 통신을 하여 정보를 교환하는 방식을 뜻힙니다.

Ajax를 통신을 하기 위해서는 Javascript에서는 XmlHttpRequest를 이용하여 정보를 주고 받습니다.

<!doctype html>
<html>
 <head>
  <title>Document</title>
 </head>
 <body>
  <!-- 예제를 위한 버튼 -->
  <button id="test">click</button>
  <script>
    // id가 test인 요소에 클릭 이벤틀르 추가한다.
    document.getElementById("test").addEventListener("click", ()=>{
      // ajax를 하기 위한 XmlHttpRequest 객체
      let xhttp = new XMLHttpRequest();
      // XmlHttpRequest의 요청
      xhttp.onreadystatechange = (e)=>{
        // XMLHttpRequest를 이벤트 파라미터에서 취득
        let req = e.target;
        // 콘솔 출력
        console.log(req);
        // 통신 상태가 완료가 되면.
        if(req.readyState === XMLHttpRequest.DONE) {
          // Http response 응답코드가 200(정상)이면
          if(req.status === 200) {
            // response 결과를 콘솔에 출력
            console.log(req.response);
            // json 타입이므로 object 형식으로 변환
            console.log(JSON.parse(req.responseText));
          }
        }
      }
      // http 요청 타입과 주소, 동기식 여부
      xhttp.open("GET", "test.json", true);
      // xml 형식을 받을 경우
      //xhttp.overrideMimeType('text/xml');
      // http 요청
      xhttp.send();
    });
  </script>
 </body>
</html>
{"test":"hello world"}

버튼을 클릭하면 test.json을 GET방식으로 비동기식 요청을 하게 됩니다. 그러면 요청이 완료가 되면(req.readyState의 값이 4) 응답 코드를 확인(200 정상)하고 결과를 콘솔에 출력했습니다.


먼저 XmlHttpRequest의 요청에 대한 응답 상태는 총 0부터 4까지의 값이 있습니다.

응답상태 설명
XMLHttpRequest.UNSENT (0) request가 초기화되지 않음
XMLHttpRequest.OPENED (1) 서버와 연결를 함
XMLHttpRequest.HEADERS_RECEIVED (2) 서버가 요청을 받음
XMLHttpRequest.LOADING (3) 서버의 응답을 기다림
XMLHttpRequest.DONE (4) 서버의 응답이 완료됨

Http의 응답 코드는 워낙 많으니 위키 백과를 참조해 주세요.

링크 - https://ko.wikipedia.org/wiki/HTTP_상태코드

기본적을 응답코드 200은 정상이고 404는 페이지 없음(Not found)입니다. 404는 워낙 유명한 응답 코드 번호이네요..


결과에 대해서는 response, responseText, responseXML의 방식이 있습니다.

Text타입이 아닌 이미지나 엑셀 파일, PDF 파일등은 response를 통해서 바이너리로 받은 다음 파일로 저장하면 됩니다.

그리고 그 외 Text타입이면 responseText를 통해 받습니다. 위 예제는 JSON타입의 데이터를 문자열로 받았기 때문에 responseText로 받고 JSON.parse를 오브젝트화 했습니다.

responseXML의 경우는 해더의 context-type이 "text/xml"으로 되거나 overrideMimeType를 "text/xml"으로 설정하면 responseXML으로 받습니다.


xhttp.open() 함수의 첫번째 파라미터는 요청 메소드, 즉 GET과 POST의 값이 있습니다. 그리고 두번째 파라미터는 요청 URL입니다.

마지막으로 세번째는 요청 비동기와 동기의 형식입니다.

이 세번째 파라미터는 기본적으로 true로 비동기 형식입니다. XmlHttpRequest의 요청의 관계없이 send함수가 불리면 그 다음 스탭으로 넘어갑니다.

하지만 false로 동기 형식이 되면 send함수가 실행되고 XmlHttpRequest의 요청의 요청이 XMLHttpRequest.DONE (4)이 되면 다음 스탭으로 넘어갑니다.

즉 완료가 될 때까지 send함수에서 멈추게 됩니다.

<!doctype html>
<html>
 <head>
  <title>Document</title>
 </head>
 <body>
  <!-- 예제를 위한 버튼 -->
  <button id="test">click</button>
  <script>
    // id가 test인 요소에 클릭 이벤틀르 추가한다.
    document.getElementById("test").addEventListener("click", ()=>{
      // ajax를 하기 위한 XmlHttpRequest 객체
      let xhttp = new XMLHttpRequest();
      // http 요청 타입과 주소, 동기식 여부
      xhttp.open("POST", "test.json", false);
      // http 요청
      xhttp.send();
      // response 결과를 콘솔에 출력
      console.log(xhttp.responseText);
    });
  </script>
 </body>
</html>

동기식으로 ajax를 취득하여 결과가 나왔습니다. 근데 Deprecation에러가 발생했네요.. 아마도 비동기식의 ajax를 동기식으로 처리한다고 사용하지 말라는 경고 메시지입니다. 크게 신경을 쓰지 않아도 됩니다만 신경이 쓰인다면 Promise를 통해서 동기식으로 만들어도 됩니다.

<!doctype html>
<html>
 <head>
  <title>Document</title>
 </head>
 <body>
  <!-- 예제를 위한 버튼 -->
  <button id="test">click</button>
  <script>
    // ajax는 비동기식이지미나 Promise를 통해 동기처럼 만든다.
    function ajax(){
      // Promise를 추가
      return new Promise((resovle)=>{
        // ajax를 하기 위한 XmlHttpRequest 객체
        let xhttp = new XMLHttpRequest();
        // XmlHttpRequest의 요청
        xhttp.onreadystatechange = (e)=>{
          // XMLHttpRequest를 이벤트 파라미터에서 취득
          let req = e.target;
          // 통신 상태가 완료가 되면.
          if(req.readyState === XMLHttpRequest.DONE && req.status === 200) {
            // JSON 오브젝트 형식으로 리턴
            resovle(JSON.parse(req.response));
          }
        }
        // http 요청 타입과 주소, 동기식 여부는 생략하면 true입니다.
        xhttp.open("GET", "test.json");
        // http 요청
        xhttp.send();
      });
    }
    // id가 test인 요소에 클릭 이벤틀르 추가한다.
    document.getElementById("test").addEventListener("click", ()=>{
      // ajax를 호출해서 결과를 console에 추가한다.
      (async ()=>{
        let data = await ajax();
        console.log(data);
      })();
    });
  </script>
 </body>
</html>

원래라면 async를 사용하거나 Promise + setTimeout를 통해 async + await를 사용합니다. 그러나 send를 하면 onreadystatechange의 이벤트를 호출하기 때문에 setTimeout를 사용하기가 애매합니다. setTimeout도 이벤트 큐에 보내는 형식이기 때문입니다.

클릭 이벤트에서 await 함수를 주어서 동기식 처럼 변환했습니다.


xhttp.open에서 POST형식으로 보내게 되면 send에는 form데이터가 들어갑니다.

<!doctype html>
<html>
 <head>
  <title>Document</title>
 </head>
 <body>
  <!-- 예제를 위한 버튼 -->
  <button id="test">click</button>
  <script>
    // id가 test인 요소에 클릭 이벤틀르 추가한다.
    document.getElementById("test").addEventListener("click", ()=>{
      // ajax를 하기 위한 XmlHttpRequest 객체
      let xhttp = new XMLHttpRequest();
      // XmlHttpRequest의 요청
      xhttp.onreadystatechange = (e)=>{
        // XMLHttpRequest를 이벤트 파라미터에서 취득
        let req = e.target;
        // 콘솔 출력
        console.log(req);
        // 통신 상태가 완료가 되면.
        if(req.readyState === XMLHttpRequest.DONE) {
          // Http response 응답코드가 200(정상)이면
          if(req.status === 200) {
            // response 결과를 콘솔에 출력
            console.log(req.response);
            // json 타입이므로 object 형식으로 변환
            console.log(JSON.parse(req.responseText));
          }
        }
      }
      // http 요청 타입과 주소, 동기식 여부
      xhttp.open("POST", "test.json");
      // xml 형식을 받을 경우
      //xhttp.overrideMimeType('text/xml');
      // http 요청 (form 데이터를 여기에 넣습니다.)
      xhttp.send("test=1&data=hello world");
    });
  </script>
 </body>
</html>

여기까지 Javascript에서 비동기 통신(Ajax)를 하는 방법에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.