AJAX 이야기


Notice: Undefined index: lang in /home/taggon/www/wordpress/wp-content/plugins/wp-highlightjs/wp_highlight.js.php on line 119

Notice: Undefined index: lang in /home/taggon/www/wordpress/wp-content/plugins/wp-highlightjs/wp_highlight.js.php on line 119

Notice: Undefined index: lang in /home/taggon/www/wordpress/wp-content/plugins/wp-highlightjs/wp_highlight.js.php on line 119

Notice: Undefined index: lang in /home/taggon/www/wordpress/wp-content/plugins/wp-highlightjs/wp_highlight.js.php on line 119

AJAX?
우선 AJAX라는 것의 정의를 말하면 웹페이지에서 HTTP 프로토콜을 사용해 XML 데이타를 동적으로 로딩할 수 있는 기술이라고 할 수 있다. Asynchronous JavaScript and XML 라는 이름에서 보듯 비동기적이며, Javascript와 XML을 이용한다.

AJAX 에 대해서 온라인 백과사전인 Wikipedia에서는 이렇게 정의하고 있다.

사용자와 상호교류가능한(interactive) 웹 어플리케이션을 만들기위한 웹 개발 기술로서, 다음과 같은 요소로 이루어진다.

  • XHTML(혹은 HTML)과 CSS로 정보가 표현된다.
  • 화면에 정보를 표시하기 위해 자바스크립트로 DOM(Document Object Model)을 동적으로 다룬다.
  • 웹서버와의 비동기적인 자료교환을 위해서 XMLHttpRequest 를 사용한다. (일반적으로 XML을 다루지만, HTML, 일반텍스트, JSON, EBML등 어떤 포맷이건 상관없다)

발생배경
그럼 왜 이 기술이 각광받고 있는가 하면 HTML과 HTTP의 한계때문이다. HTML은 애초에 어플리케이션 보다는 문서의 표현을 중심에 두고 만들어졌기 때문에 사용자와의 능동적인 작용을 하지 못했었다. 이에 Javascript 가 추가되고 해서 어느 정도 동적인 액션이 가능해졌지만 그 역시 HTTP의 한계를 넘기엔 부족했다.

HTTP는 프로토콜 특성상 세션의 개념이 없다. 오직 요청과 응답만 있어서 내가 웹서버에 요청한 자료를 웹서버로부터 전달받으면 그것으로 그 접속은 종료해버린다. 즉, 텔넷, SSH 혹은 FTP처럼 내가 그 서버에 계속 접속해있는 상태가 아닌 것이 된다는 것이다. 그래서 이를 보완하기 위해 사용한 기술이 쿠키, 세션 같은 것이었는데, 그 동안은 그것만으로도 잘 버텨왔다.

문제는 웹의 발전과 더불어 사용자들의 요구가 너무나 다양해졌다는데 있다. 그 이전에는 실행파일이라는 형태로 사용자의 컴퓨터에서 실행되던 프로그램들을 웹 어플리케이션이 대체하게 되면서 사용자들은 웹이 좀 더 능동적이며, 사용자의 액션에 즉각즉각 반응할 수 있게 되기를 원했고 알다시피 현재의 기술로는 불가능하거나 그렇지 않더라도 몹시 번거로운 작업이었다.

자바애플릿이 한 때 이러한 욕구를 충족시켜줄만한 기술로 주목받았었지만, 너무 느리고 때때로 웹브라우저를 다운시켜버리는 등 불안한 요소가 많았으며, 자바를 할 줄 아는 인력이 따로 필요했다는 점에서 인기가 오래 지속되지는 못했다(물론, 지금도 널리 사용중이다). 이에 비해 AJAX는 자바스크립트를 사용하던 웹 개발자들이 약간의 노력만으로도 충분히 능동적인 웹 어플리케이션을 만들 수 있다는 장점이 있다. 게다가 따로 플러그인이나 VM따위를 설치할 필요도 없으며, Javascript 를 사용하기 때문에 잘못된 어플리케이션이라 해도 웹 브라우저를 다운시킬 염려가 적다.

동작원리
전통적인 웹 브라우저의 동작을 살펴보자.
먼저 웹 브라우저가 서버에 있는 문서를 요청하면 서버는 웹 브라우저에 문서를 다시 전송한다. 웹 브라우저는 요청후 원하는 문서를 전송받고 나면 서버와의 연결을 종료하는데, 이 부분이 바로 HTTP 프로토콜의 한계다. 또한, 전송받은 문서를 화면에 완전히 새로 그리면서 화면깜빡임이 발생하게 된다.

반면에 AJAX는 XMLHttp라는 Http 객체를 새로 생성해서 웹 브라우저에 요청하게 되고, 대부분의 경우 문서전체가 아닌 문서의 데이터만을 돌려받게 된다. 따라서, Javascript 를 이용해서 현재의 문서를 업데이트할 수 있고, 문서 일부의 데이터만 변경되기 때문에 사용자는 화면 깜빡임을 거의 느낄 수 없고, 웹서버와 브라우저간에 주고 받는 데이터의 양도 적어 서버 부하 및 트래픽 절감의 효과가 있다.
이 과정이 Javascript 로 통제되기 때문에 사용자의 액션에 적절히 반응할 수 있고, 또한 필요하다면 추가적으로 데이타를 불러올 수도 있어 동적이고 풍부한 웹 어플리케이션의 제작이 가능해지는 것이다.

예제코드
Microsoft Internet Explorer 의 최신버전에서는 AJAX를 위한 XMLHttpRequest 객체를 바로 생성할 수 없다. 따라서 AcitveX 객체를 생성해주어야 한다.
var req = new ActiveXObject("Microsoft.XMLHTTP");
또한 XML 라이브러리인 MSXML에 이 객체가 포함되어있어 라이브러리 버전에 따라 MSXML2.XMLHTTPMSXML3.XMLHTTP 를 사용할 수 있다. msxml2.dll 파일은 Windows XP HomeEdition 이상부터, XMLHTTPRequest 객체가 포함된 msxml.dll 은 Windows 98 Second Edition 부터 기본으로 포함되어있다. 가급적 최신 라이브러리를 사용한는 편이 좋다고 생각하는 사람들은 MSXML4 버전부터 역순으로 버전을 다운시켜가며 객체를 생성하는 방법을 사용해본다.


var req = null;
var libs = new Array('MSXML4','MSXML3','MSXML2','Microsoft');
for (var i=0; i <libs.length; i++) {
....try {
........req = new ActiveXObject(libs[i]+".XMLHTTP");
........break;
....} catch(e) { continue; }
}
if (req == null) alert("XMLHttpRequest 객체를 생성할 수 없습니다.");

아직까지 try ~ catch 구문을 모르는 사람에게는 익숙하지 않을 수도 있겠으나 try 구문 안쪽을 실행하다 에러가 발생하면 catch 구문 쪽으로 이동해서 예외 처리를 한다. 위 코드를 해석하면, “객체를 생성하다가 (객체가 지원되지 않아) 에러가 발생하면 다음 객체로 시도해보라” 가 될 수 있다.

이제 다른 브라우저의 코드를 살펴보기로 하자. 위의 Internet Explorer 와는 달리 브라우저에서 직접 XMLHttpRequest 를 지원해준다. 따라서 아래와 같은 코드를 이용해 바로 객체를 생성할 수 있다.
var req = new XMLHttpRequest();

이제 위의 IE 전용 코드를 참고해 다양한 브라우저에서 사용할 수 있는 코드를 만들어보자. 실제로 많은 스크립트들이 MSXML2.XMLHTTPMicrosoft.XMLHTTP만 지원하고 있고(OS에 기본 설치된 것이므로) 큰 개선이나 성능의 차이가 있는 것은 아니니 여기서도 두가지 경우만 고려하기로 한다.


function getXMLHttp()
{
....var req = null;

....try { req = new ActiveXObject("MSXML2.XMLHTTP"); }
....catch(e) { try { req = new ActiveXObject("Microsoft.XMLHTTP"); } }
....catch(e) { try { req = new XMLHttpRequest(); } }
....catch(e) { req = null; }

....if (req == null) {
........// XMLHttp 가 지원되지 않을때
........return false;
....}

....return req;
}


이제 XMLHttpRequest 객체를 생성했다. 그 다음에는 이 객체를 이용해 데이타를 전송하고 결과값을 받는 간단한 코드를 작성해보자.
var req = getXMLHttp();
req.open("GET", "http://mygony.com/ajax/sample.xml", true);
req.onreadystatechange = function() {
....if (req.readyState == 4) {
........alert("데이타를 읽었다!!");
....}
}
req.send(null);

위의 코드를 보면 두가지 메소드와 한가지의 이벤트를 사용했음을 알 수 있다. 우선 open 을 보자. 소켓을 생성하고 URL과 전송방식을 지정해주기는 하지만 실제로 전송이 일어나지는 않는다.

Method Description
abort() 현재의 요청을 중단
getAllResponseHeaders() 헤더를 문자열로 반환
getResponseHeader(“headerLabel”) 지정한 라벨의 헤더값을 문자열로 반환
open(“method”, “URL”[, asyncFlag[, “userName”[, “password”]]]) 전송하기 전에 대상 URL, 전송방법, 기타 몇가지 속성을 지정한다.
setRequestHeader(“label”, “value”) 라벨과 값을 붙여서 전송할 헤더를 추가한다.

메소드에 대한 설명은 위의 표를 참고하면 될 것이다. 실제로 send 에서 전송할 데이터를 입력하는데, “key1=val1&key2=val2” 와 같은 식으로 Label+Value 의 형태를 취하면 된다. 위 예제에서는 전송할 데이터가 없어서 null로 두었다.
onreadystatechange 이벤트를 잘보면 readyState를 체크하고 있는 것을 알 수 있는데, readyState의 값이 4인가를 체크하는 이유는 4일때가 전송이 모두 완료된 시점이기 때문이다. 나머지 상태값들은 아직 소켓이 초기화되지 않거나 전송이 완료되지 않은 상태이므로 크게 고려하지 않아도 될 것이다.

전송받은 데이터는 DOM 형태로 사용하거나 raw text 를 그대로 이용할 수 있다. 위 코드에서 이벤트 핸들러를 아래와 같이 바꾸어보자.


req.onreadystatechange = function() {
....if (req.readyState == 4) {
........alert(req.responseXML.childNodes.length);
....// alert(req.responseText);
....}
}

responseText 를 이용하면 raw text 를 그대로 이용할 수 있고, responseXML 을 이용하면 DOM형태의 접근이 가능하다. 물론, DOM을 이용하기 위해서는 전송받은 결과가 XML 문서여야 한다.
이 때 한글을 사용하는 개발자가 주의할 것이 있는데, 전송자료는 반드시 기본값이 UTF-8로 인코딩되어야 한다. 표시되고 있는 페이지의 인코딩에 관계없이 전송하는 데이터는 반드시 권장사항이 UTF-8 이다. 페이지의 인코딩이 UTF-8 이 아니라면 브라우저에서 내부적으로 인코딩 변환이 일어나므로, 변환문제에 관해서는 고민하지 않아도 된다. (추가)XML을 이용할 경우 인코딩을 명시해주므로 UTF-8 이 아니라도 상관없지만, 자료의 호환을 위해서는 역시 UTF-8을 사용해주는게 좋을 것 같다.

cf) 더 자세한 속성/메소드에 대해서는 MSDN 이나 Apple 개발자 사이트 참고

버전호환
아래는 XMLHttp가 지원되고 호환되는 브라우저의 목록이다. 최신버전의 브라우저에서는 거의 전부라고 해도 과언이 아닐 정도로 많은 브라우저들이 지원하지만, 버전이 낮은 브라우저의 경우 지원하지 않을 수도 있음을 명심하자.

Apple Safari 1.2+
Microsoft Internet Explorer 5.0+ (Windows)
Mozilla 0.7.3+ – Firefox, Camino 등 포함
Opera 7.60 P1+

마치며
최신의 웹브라우저들이 앞다투어 XMLHttp 를 지원하는 것만 보아도 알 수 있듯이 AJAX는 앞으로도 더욱 널리 쓰이게 될 것이다. 점차 현실화되고 있는 Rich Internet Application 환경에서 AJAX는 현시점의 가장 효율적인 대안이 아닐까 한다.@

  1. Pingback: link
  2. 마소에서 보니 get방식에는 encodeURIComponent를 꼭 붙여주더군요;; (맞나?) 프로젝트에 get방식으로 사용해 본 결과 euc-kr과 utf-8 의 코드 충돌 문제로 encodeURIComponent를 사용하지 않으면 바보가 됩니다;;;;;

    그래서 그냥 생각하지 않고 포스트로 보내고 있어요;

  3. for (var i=0; i<objs.length; i++) {
    try {
    req = new ActiveXObject(libs[i]+".XMLHTTP");
    } catch(e) { continue; }
    }

    위 코드 대로라면 catch(e) { continue; } 의 의미가 없는 거 아닌가요 +_+? 객체 할당 성공 여부와 상관없이 모든 방식으로 객체를 만들려고 시도할 듯 한데요

  4. Pingback: The Old New Think
  5. Pingback: 해뜰녘
  6. responseXML 을 사용할때는 꼭 UTF-8만 쓸수있는건 아니에요 : ) 문제가 되는경우는 responseText 일때죠
    실제로 euc-kr xml을 불러서 트리 데이타를 잘 그려 사용하고 있고요..
    저는 async 하지 않은 방법으로도 이용하므로 Ajax 라는 용어를 과감히 버리고 HTTP 라는 모듈을 만들어 쓰는중입니다.

Leave a Reply