JavaScript: Ajax

    JavaScript: Ajax

    2018, Mar 20    

    ์ฐธ๊ณ ํ•œ ๊ธ€

    Ajax๋ž€?

    Ajax๋Š” โ€˜Asynchronous JavaScript and XMLโ€™์˜ ์•ฝ์ž๋กœ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ ๊ธฐ๋ฒ•์˜ ํ•˜๋‚˜๋‹ค. Ajax๋Š” ๋…๋ฆฝ๋œ ๊ธฐ์ˆ ์„ ์˜๋ฏธํ•˜๊ธฐ๋ณด๋‹จ ์—ฌ๋Ÿฌ ๊ธฐ์ˆ ์˜ ๋ฌถ์Œ์„ ์ง€์นญํ•˜๋Š” ์šฉ์–ด์— ๊ฐ€๊น๋‹ค. ์‹ค์ œ๋กœ Ajax๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ๋Š” HTML, CSS, DOM, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ, XML, XSLT, XPath, XMLHttpRequest ๋“ฑ์ด ์‚ฌ์šฉ๋œ๋‹ค.

    Ajax๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋จผ์ € ๋ธŒ๋ผ์šฐ์ €์˜ ๋‚ด์žฅ ํ•จ์ˆ˜๋กœ XMLHttpRequest ๊ฐ์ฒด(์˜์™ธ์ง€๋งŒ XMLHttpRequest๋Š” ๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ์—์„œ ์ฒ˜์Œ ๋งŒ๋“ค์—ˆ๋‹ค)๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค. ๊ณผ๊ฑฐ์—” ActiveXObject๋ผ๋Š” ์†Œ๋ฆ„ ๋‹๋Š” ์ด๋ฆ„์˜ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ, ์›น ์‚ฌ์šฉ์ž์˜ ์ตœ์†Œ ํ™˜๊ฒฝ์ด IE8์ธ ์š”์ฆ˜์—” ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

    var xmlReq = false;
    if (window.XMLHttpRequest) { // Non-Microsoft browsers
      xmlReq = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
      try {
        xmlReq = new ActiveXObject('Msxml2.XMLHTTP');
        // XMLHttpRequest in later versions of Internet Explorer
      } catch (e1) {
        try {
          xmlReq = new ActiveXObject('Microsoft.XMLHTTP');
          // Try version supported by older versions of Internet Explorer
        } catch (e2) {
          // Unable to create an XMLHttpRequest with ActiveX
        }
      }
    }
    

    ๋งˆ์†Œ๊ฐ€ ํญ์ฃผํ•˜๋˜ 2000๋…„๋Œ€์—๋‚˜ ์“ฐ์ด๋˜ ์ฝ”๋“œ. ์ง€๊ธˆ์€ ๊ทธ๋ƒฅ ์•„๋ž˜ ํ•œ ์ค„๋กœ ํ•ด๊ฒฐ๋œ๋‹ค:

    var xhr = new XMLHttpRequest();
    

    ์•„๋ž˜ ๋‘ ์˜ˆ์‹œ๋ฅผ ๊ฐ๊ฐ test1.html, test2.html๋กœ ๋งŒ๋“ค์–ด์„œ ํ…Œ์ŠคํŠธ ํ•ด๋ณด์ž:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>test1.html</title>
    <script>
      function loadDoc() {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function() {
          if (xhr.readyState == 4 && xhr.status == 200) {
            document.getElementById('demo').innerHTML = xhr.responseText;
          }
        };
        xhr.open('GET', 'test2.html');
        xhr.send();
      }
    </script>
    </head>
    <body>
    <button onclick="loadDoc()">who r u</button>
    <div id="demo">
    </div>
    </body>
    </html>
    
    <h2>i am waldo</h2>
    

    XMLHttpRequest์˜ ํ”„๋กœํผํ‹ฐ

    XMLHttpRequest.open()

    XMLHttpRequest.open( method, url [ , async ] )
    
    • method: HTTP ๋ฉ”์„œ๋“œ ํƒ€์ž… (get/post)
    • url: ์„œ๋ฒ„ ๊ฒฝ๋กœ
    • async: ๋น„๋™๊ธฐ ์—ฌ๋ถ€. (true/false)

    request์˜ ์œ ํ˜•์„ ์ง€์ •ํ•œ๋‹ค. send()๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋‚ ๋ฆฌ๊ธฐ ์ „, ์–ด๋””์— ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•˜๋Š”์ง€๋ฅผ ์ •ํ•˜๋Š” ๋ฉ”์„œ๋“œ. method์™€ url์€ ํ•„์ˆ˜์ง€๋งŒ async๋Š” ๊ธฐ๋ณธ๊ฐ’์ด true๋กœ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋Š” ํ•ญ๋ชฉ์ด๋‹ค. async๋ฅผ false๋กœ ์ง€์ •ํ•  ๊ฒฝ์šฐ send() ํ›„ ์Šคํฌ๋ฆฝํŠธ์˜ ์ง„ํ–‰์„ ์ค‘๋‹จํ•˜๋ฉฐ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์‘๋‹ต์ด ์˜ฌ ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐํ•œ๋‹ค.

    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'test2.html');
    // GET ๋ฐฉ์‹์œผ๋กœ ์š”์ฒญํ•  URL ์„ค์ •
    

    XMLHttpRequest.setRequestHeader()

    XMLHttpRequest.setRequestHeader( header, value )
    
    • header: ํ—ค๋”์˜ ์ด๋ฆ„
    • value: ํ—ค๋”์˜ ๊ฐ’

    HttpRequest ํ—ค๋”์˜ ๊ฐ’์„ ์„ค์ •ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋กœ ๋ฐ˜๋“œ์‹œ open()๋ณด๋‹ค ๋‚˜์ค‘์— ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•œ๋‹ค.

    XMLHttpRequest.send()

    XMLHttpRequest.send( [ string ] )
    
    • string: ํผ ๋ฐ์ดํ„ฐ๋กœ ์ „์†กํ•  ๋ฌธ์ž์—ด

    ์„œ๋ฒ„๋กœ request ์†ก์‹ . open()์—์„œ ์„ค์ •ํ•œ ๊ฐ’์— ๋”ฐ๋ผ ์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•œ๋‹ค. string์€ HTTP ๋ฉ”์„œ๋“œ ํƒ€์ž…์ด POST์ผ ๊ฒฝ์šฐ์—๋งŒ ๋ช…์‹œํ•˜๋ฉฐ ํผ ๋ฐ์ดํ„ฐ๋กœ ๊ฐ„์ฃผ๋œ๋‹ค. POST ๋ฐฉ์‹์ผ ๋• ์•„๋ž˜ ์˜ˆ์‹œ์ฒ˜๋Ÿผ setRequestHeader()๋กœ ์ปจํ…์ธ  ํƒ€์ž…์„ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ์„œ๋ฒ„์—์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋‹ค. ๊ทธ๋ฆฌ๊ณ  string์€ ๋ฐ˜๋“œ์‹œ ์ฟผ๋ฆฌ์ŠคํŠธ๋ง ํ˜•ํƒœ๋กœ ์ž‘์„ฑ๋˜์–ด์•ผ ํ•œ๋‹ค.

    var xhr = new XMLHttpRequest();
    xhr.open('POST', 'test4.html');
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.send('first=111&second=222');
    

    XMLHttpRequest.abort()

    xhr.abort();
    

    ์ˆ˜ํ–‰ ์ค‘์ธ ํ†ต์‹ ์„ ์ค‘๋‹จํ•œ๋‹ค. ์ด๋ฏธ ๋‚ ๋ผ๊ฐ„ request๋Š” ์–ด์ฉ” ์ˆ˜ ์—†๊ณ  ๋‹จ์ง€ ์‘๋‹ต์„ ๋ฌด์‹œํ•  ๋ฟ. ํ†ต์ˆ˜

    XMLHttpRequest.getAllResponseHeaders()

    response ํ—ค๋” ์ •๋ณด๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. send()๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „์—๋Š” ๋นˆ ๊ฐ’์„ ๋ฆฌํ„ดํ•œ๋‹ค. ์ฆ‰, ์„œ๋ฒ„์˜ ์‘๋‹ต ํ›„์—๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฉ”์„œ๋“œ

    xhr.getAllResponseHeaders();
    // "Server: Apache-Coyote/1.1
    // Content-Type: text/html;charset=UTF-8
    // Content-Length: 22
    // Date: Wed, 27 Jan 2016 15:19:02 GMT
    // "
    

    XMLHttpRequest.getResponseHeader()

    XMLHttpRequest.getResponseHeader( header )
    
    • header: ํ—ค๋”์˜ ์ด๋ฆ„

    response ํ—ค๋” ์ค‘ ํŠน์ •ํ•œ ๊ฐ’๋งŒ ๋ฆฌํ„ดํ•œ๋‹ค.

    xhr.getResponseHeader('Content-Type')
    // "text/html;charset=UTF-8"
    

    XMLHttpRequest.timeout

    ์ง€์ •ํ•œ ์‹œ๊ฐ„์„ ์ดˆ๊ณผํ•˜๋ฉด XMLHttpRequestEventTarget.ontimeout์„ ํ˜ธ์ถœํ•œ๋‹ค. ๋‹จ์œ„๋Š” ๋ฐ€๋ฆฌ์ดˆ(milliseconds)

    XMLHttpRequest.responseText

    ์„œ๋ฒ„์˜ ์‘๋‹ต์„ ๋ฌธ์ž์—ด๋กœ ๋ฆฌํ„ด.

    XMLHttpRequest.responseXML

    ์„œ๋ฒ„์˜ ์‘๋‹ต์„ XMLDocument๋กœ ํŒŒ์‹ฑํ•ด ๋ฆฌํ„ด. ํŒŒ์‹ฑ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉด null์„ ๋ฆฌํ„ดํ•œ๋‹ค.

    XMLHttpRequest.status

    ์‘๋‹ต์˜ ์ƒํƒœ์ฝ”๋“œ๋ฅผ ์ˆซ์ž๋กœ ๋ฆฌํ„ดํ•œ๋‹ค.

    XMLHttpRequest.statusText

    ์‘๋‹ต์˜ ์ƒํƒœ์ฝ”๋“œ๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ฆฌํ„ดํ•œ๋‹ค. ๋‹จ์ˆœํžˆ ์ˆซ์ž๋ฅผ ๋ฌธ์ž์—ด๋กœ ํ‘œํ˜„ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ƒํƒœ์ฝ”๋“œ๊ฐ€ ๋ญ˜ ์˜๋ฏธํ•˜๋Š”์ง€ ๋‚˜ํƒ€๋‚ธ๋‹ค. ๊ฐ€๋ น ์ƒํƒœ์ฝ”๋“œ๊ฐ€ 404์ผ ๋•Œ ๋ฆฌํ„ด๋˜๋Š” ๊ฐ’์€ โ€œNot Foundโ€

    XMLHttpRequest.readyState

    XMLHttpRequest์˜ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

    • 0: request not initialized.
    • 1: server connection established
    • 2: request received
    • 3: processing request
    • 4: request finished and response is ready

    Attach callback function

    ํ†ต์‹  ํ›„ ์„ฑ๊ณต ํ˜น์€ ์‹คํŒจ์— ๋”ฐ๋ฅธ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ–ˆ์„ ๋•Œ ์ฝœ๋ฐฑ์œผ๋กœ ํ˜ธ์ถœ๋˜๋Š” ํ”„๋กœํผํ‹ฐ์— ํ•จ์ˆ˜๋ฅผ ํ• ๋‹นํ•˜๋ฉด ๋œ๋‹ค. ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ํ• ๋‹นํ•˜๋Š” ๋ฐฉ๋ฒ•์€ XMLHttpRequest์˜ onreadystatechange() ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜๊ฑฐ๋‚˜ XMLHttpRequestEventTarget์˜ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•, ๊ทธ๋ฆฌ๊ณ  EventTarget.addEventListener() ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

    XMLHttpRequest.onreadystatechange

    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
      if (xhr.readyState == 4 && xhr.status == 200) {
        console.log('complete');
      }
    };
    xhr.open('GET', 'http://somewhere');
    xhr.send();
    

    onreadystatechange()๋Š” XMLHttpRequest์˜ ํ”„๋กœํผํ‹ฐ๋กœ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ €์žฅํ•œ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” readyState์˜ ๊ฐ’์ด ๋ณ€ํ•  ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋˜๋‹ˆ ๊ทธ๋Œ€๋กœ ์‹คํ–‰๋˜๋„๋ก ํ•˜๋ฉด ์•ˆ ๋˜๊ณ  readyState์˜ ๊ฐ’์„ ์ฒดํฌํ•˜๋Š” ์กฐ๊ฑด ๋ถ„๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

    EventTarget.addEventListener()

    EventTarget.addEventListener( eventType, callback )
    
    • eventType: callback์ด ์‹คํ–‰๋  ์ด๋ฒคํŠธ์˜ ์œ ํ˜• (ex: โ€˜loadโ€™)
    • callback: eventType์— ์ง€์ •ํ•œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์‹คํ–‰ํ•  ํ•จ์ˆ˜

    addEventListener()๋Š” IE8์—์„œ ์ง€์›๋˜์ง€ ์•Š์œผ๋‹ˆ ์ฃผ์˜ํ•  ๊ฒƒ. ์•…์˜ ์ถ•

    function reqListener () {
      console.log(this.responseText); // this == xhr
    }
    
    var xhr = new XMLHttpRequest();
    xhr.addEventListener('load', reqListener);
    xhr.open('GET', 'http://example.org/example.txt');
    xhr.send();
    

    XMLHttpRequestEventTarget

    var xhr = new XMLHttpRequest();
    console.debug(xhr);
    xhr.onabort = function() {
      console.log('onabort - xhr.readyState: ' + xhr.readyState);
    };
    xhr.onerror = function() {
      console.log('onerror - xhr.readyState: ' + xhr.readyState);
      console.log('xhr.status: ' + xhr.status);
    };
    xhr.onloadstart = function() {
      console.log('onloadstart - xhr.readyState: ' + xhr.readyState);
    };
    xhr.onloadend = function() {
      console.log('onloadend - xhr.readyState: ' + xhr.readyState);
    };
    xhr.onprogress = function(event) {
      console.log('progress - xhr.readyState: ' + xhr.readyState);
      console.log('loaded: ' + event.loaded);
      console.log('size: ' + event.size);
    };
    xhr.onload = function() {
      console.log('complete');
    };
    xhr.open('GET', 'test2.html');
    xhr.send();
    

    XMLHttpRequestEventTarget์€ XMLHttpRequest์˜ ์Šˆํผํด๋ž˜์Šค๋‹ค. ์ƒ์†๋ฐ›๋Š” ๋ฉ”์„œ๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค:

    • onabort: abort ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ํ˜ธ์ถœ๋œ๋‹ค.
    • onerror: ์„œ๋ฒ„์˜ ์‘๋‹ต์ด 200์ด ์•„๋‹ ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค.
    • onloadstart: XHR ์š”์ฒญ์„ ์‹œ์ž‘ํ•  ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค.
    • onloadend: XHR ์š”์ฒญ์ด ์™„๋ฃŒ๋˜๋ฉด ํ˜ธ์ถœ๋œ๋‹ค. onload()์™€ ๋‹ค๋ฅด๊ฒŒ ์„ฑ๊ณต/์‹คํŒจ ์ƒ๊ด€์—†์ด ํ˜ธ์ถœ๋œ๋‹ค.
    • onprogress: onloadstart()์™€ onloadend() ์‚ฌ์ด์— ํ˜ธ์ถœ๋œ๋‹ค. ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ProgressEvent๋ฅผ ์ „๋‹ฌ๋ฐ›์œผ๋ฉฐ ์ด ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋Š” ๋ธŒ๋ผ์šฐ์ €๋งˆ๋‹ค ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.
    • onload: XHR ์š”์ฒญ์ด โ€˜์„ฑ๊ณต์ ์œผ๋กœโ€™ ์™„๋ฃŒ๋˜๋ฉด ํ˜ธ์ถœ๋œ๋‹ค. ์ฆ‰ XHR.status๊ฐ€ 200์ผ ๋•Œ๋งŒ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ.
    • ontimeout: XHR.timeout์œผ๋กœ ์„ค์ •ํ•œ ์‹œ๊ฐ„ ๋‚ด์— ์‘๋‹ต์ด ๋„์ฐฉํ•˜์ง€ ์•Š์œผ๋ฉด ํ˜ธ์ถœ๋œ๋‹ค. ์š”์ฒญ์€ ์‹คํŒจํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋˜๋ฉฐ onprogress()์™€ onload()๋Š” ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค.