AJAX 기본

Toggle Space Navigation Tree
Space Map

Ajax(Asynchronous JavaScript + XML) 기본

Table of Contents

1. Ajax란? ('에이젝스'라고 발음함)

'Ajax'란 이름은 2005년 2월 18일에 Adaptive Path사의 제시 제임스 가렛(Jesse James Garrett)이 쓴 블로그 형식의 칼럼 "Ajax: A New Approach to Web Applications"에 처음 등장, 이후 세상에 처음 Ajax라는 말이 알려지기 시작했다.
내용이 그리 길지 않으니, 반드시 일독하길 바란다.

Ajax는 'Asynchronous JavaScript + XML'을 줄인말로써, "서버 처리를 기다리지 않고 비동기(Asynchronous)요청이 가능하다"란 의미로 이해하면되겠다.
여기에서, JavaScript And XML이 아닌, plus로 되어 있는건 제임스 가렛의 다른 의도가 있는걸까, 단지 귀찮아서 '+'로 표시했을까? 아직 알수 없다. --;;

동기/비동기 통신 매커니즘

  • 기존동기통신 방식(classic web application model - synchronous) 에 대해선 잘 알고 있으리라 생각된다.
    Browser에서 user에 의해 request가 발생하면, server에서 요청을 처리한 후 reponse를 돌려주고, 이 결과를 Browser에 display하는 방식으로써, 화면이 깜빡이며 처리결과를 출력하게되는데 화면전환을 하지않도록 하기 위해 대체로 <iframe/>을 많이 사용하는 추세이다.
  • Ajax비동기 통신 방식(Ajax web application model - asynchronous)
    Browser에서 일어난 input이란 event에 대해, Ajax Engine이 요청을 Catch해서 server로 request를 전달해주고, server가 처리한 response를 보내주면 Ajax Engine이 받아 Browser로 출력해주는 방식이다. 이때, Ajax Engine이 서버와 통신하는 요소기술로 javascipt사용되기때문에 화면전환이 없는것이다.

이 그림에서 개인적으론 이해가 안되는 부분이 있었다.
처음 event(input)가 발생하고 server에서 요청을 처리중인데, Ajax Engine은 이미 Browser에게 무언가를 display 해버린것이다.
헉, 그렇담 Ajax는 서버에서 데이터 추출을 다 하기도 전에 Browser에 display를 먼저 해주는 놀라운 기능을 갖고 있는것인가...?
아마도 그건 아닐거고, 이런 상황을 생각해볼순 있겠다.

combo box에서 어떠한 값을 선택(click event발생)했을때 Ajax Engine이 서버의 어떠한 정보를 가져오도록한 경우, 서버측에서는 결과를 추출해내기 위해 무언가 작업을 하고 있을것이다. 이때, combo box옆에 input text field를 나타나게 하는것도 같이 작업하게 했다면, 서버에서 데이터가 오기 전에 input text field는 이미 화면에 display되어 있는것이다.
만약, 이 그림이 그런걸 의미하는게 아니라면... 훔, 댓글 달아주시라~~

Web Application Model 형태

  • 기존 Web App. model 은 user가 'HTTP Request'를 발생시키면 서버에서 처리한 후, HTML+CSS data의 형태로 Browser에 return해주어 화면에 display 하게하는 반면,
    Ajax Web App. model 은 user가 발생시킨 event가 javascript를 call하면, Ajax Engine이 이를 catch하여 서버측에 HTTP request를 보내고, 서버는 결과를 XML data형태로 만들어 Ajax Engine에게 보내준다. 그러면 Ajax Engine은 이 데이터에 HTML+CSS를 붙여 화면에 display하는 것이다.
    이때, 결과를 반드시 XML data만 사용하는건 아니고, text/csv/json의 형태로도 가능하다.

2. Ajax의 장점과 단점

장점

  • 페이지 이동없이 고속으로 화면을 전환할 수 있다.
  • 서버 처리를 기다리지 않고, 비동기 요청이 가능하다.
  • 수신하는 데이터 량을 줄일 수 있고, 클라이언트에게 처리를 위임할 수도 있다.

단점

  • Ajax를 쓸 수 없는 브라우저에 대한 문제가 있다.
  • Http클라이언트의 기능이 한정되어 있다.
  • 페이지 이동없는 통신으로 인한 보안상의 문제
  • 지원하는 Charset이 한정되어 있다.
  • 스크립트로 작성되므로 Debugging이 용이하지 않다.
  • 요청을 남발하면 역으로 서버 부하가 늘 수 있음.

3. XMLHttpRequest Object의 송수신과 Reference

XMLHttpRequest 오브젝트를 생성하여 HTTP 요청을 준비한 후, 서버에 접속하여 데이터 및 요청을 보내고, responseText 또는 responseXML 프로퍼티로 수신한다.

XMLHttpRequest Object 생성

  • 윈도우판 IE에서 XMLHttp Object 생성하는 클래스
    obj = new ActiveXObject("Microsoft.XMLHTTP")
    obj = new ActiveXObject("MSXML2.XMLHTTP")
  • 윈도우판 IE 이외에서 XMLHttp Object를 생성하는 생성자
    obj = new XMLHttpRequest()

대체로 어느 브라우저에서도 작동될 수 있도록 크로스 브라우저 라이브러리 사용

function createHttpRequest(){
    if(window.ActiveXObject){
        try{
               //win ie4, ie5, ie6
                return new ActiveXObject("Msxml2.XMLHTTP");
           }catch(e){
              try{
                return new ActiveXObject("Microsoft.XMLHTTP");
              }catch (e2) {
                return null;
              }
          }
     }else if(window.XMLHttpRequest){
       //ie, safari, kconqueror, firefox, nescape, opera
       return new XMLHttpRequest();
     }else{
       return null;
    }
}

초기화

  • obj.open(method, url, [async, [user, [ password ]]])
    설명 : 요청을 초기화해서 HTTP 메소드 및 URL 등을 설정하는 메소드

    method : GET/POST
    url : 요청대상 url
    async(옵션) : 비동기 true, 동기 false (default : true)
    user(옵션) : 인증페이지에서 사용될 사용자 이름
    password(옵션) : 인증페이지에서 사용될 암호

obj.open( 'POST', 'http://wiki.javajigi.net/' )
send('data=1')
obj.open( 'GET', 'http://wiki.javajigi.net/', true, javajigi, javajigi )

요청 헤더 설정

  • setRequestHeader(header, 값)
    설명 : 인수로 지정한 요청 헤더를 설정하는 메소드, open() 메소드가 먼저 호출되어야함.
    open() 메서드와 send() 메서드 사이에 위치하여야 함.

    header : 검색하고 싶은 헤더 이름
    값 : 설정하고 싶은 값

obj.open( 'POST', 'http://wiki.javajigi.net/' )
obj.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')

Http 요청 송신

  • send(body)
    설명 : 요청을 송신하는 메소드

    body : POST의 문자열 또는 DOMCocument, InputStream

var str = 'data=aaa&test=10'
send(str)

착신

요청이 송신되면 서버로부터 그에 대한 응답이 도착하는데, 언제 도착할지 모를때 이를 확인하기 위해 onreadystatechange이벤트를 이용한다.

  • obj.onreadystatechange = 핸들러 함수 이름
    function 핸들러 함수 이름(obj)
    Unknown macro: { /* event발생시의 처리 */ }

    설명 : readState 프로퍼티가 변화할 때 발생하여 핸들러 함수를 실행하는 이벤트
// readyState값이 4일때, responseText를 대화창에 표시
obj.onreadystatechange = func1
function func1() {
       if ( obj.readyState == 4 ) {
            alert(obj.responseText);
       }
}
  • obj.onload = 핸들러 함수 이름
    function 핸들러 함수 이름(obj)
    Unknown macro: { // event발생시의 처리 }

    설명 : 응답 헤더의 로딩을 완료했을 때 발생하여 핸들러 함수를 실행하는 이벤트
obj.onload = function (obj) {
                 alert( obj.responseText )
             }
  • value = obj.status
    설명 : 3자릿수의 숫자(long)로 HTTP상태 코드를 나타내는 프로퍼티, send()가 성공한 뒤에 얻어낼 수 있다.
    주요 HTTP 상태 코드
    코드 영문 한글설명
    200 OK 요청 성공
    401 Unauthorized 권한 없음
    403 Forbidden 접근 거부
    404 Not Found 요청 리소스 없음
    500 Internal Server Error 서버 내부 오류
obj.onreadystatechange = function () {
    if (obj.readState == 4 && obj.status == 200) {
       alert(obj.responseText)
    }
}
  • value = obj.statusText
    설명 : HTTP상태 텍스트(영문)를 나타내는 프로퍼티
    Opera 8에선 "undefined"가 반환된다. 따라서, 크로스 브라우저를 실현하는 경우에는 statusText보다 status 쪽이 안전하다.
    '주요 HTTP상태 코드' 표 참조
obj.onreadystatechange = function () {
    if (obj.readState == 4 && obj.statusText == "OK") {
       alert(obj.responseText)
    }
}
  • value = obj.readyState
    설명 : 요청의 처리상태코드(long)를 나타내는 프로퍼티
    readyState에 정의되어 있는 값
    코드 영문 한글설명
    0 UNINITIALIZED 오브젝트는 작성되어 있으나 아직 초기화되어 있지 않다.(open()이 불리지 않았음)
    1 LOADING 오브젝트가 작성되었으나 아직 send()가 불리지 않았다.
    2 LOADED send()가 불렸지만 ststus와 header가 아직 도착하지 않았다.
    3 INTERACTIVE data일부를 받았다.
    4 COMPLETED data전부를 받았다. 완전한 데이터가 이용가능

데이터

  • xmlobj = obj.responseXML
    설명 : 요청에 대한 응답을 XML(DOMDocument)로 반환한 프로퍼티

xmlobj : XML 문서(Object data Type)

샘플XML파일
<?xml version="1.0" encoding="UTF-8"?>
<test>읽어들인 XML입니다</test>
obj.onreadystatechange = function () {
    if (obj.readState == 4) {
       // 응답을 취득
        var xmlDoc = oj.responseXML
       // test tag를 배열로 set
        var nodes = xmlDoc.getElementsByTagName("test")
       // 최초 test tag의 firstChild 값을 표시한다.
       alert(nodes[0].firstChild.nodeValue)
    }
}

결과 : 알림창에 '읽어들인 XML입니다'를 띄운다.

  • value = obj.responseText
    설명 : 요청에 대한 응답을 텍스트로 돌려주는 프로퍼티
obj.onreadystatechange = function () {
    if (obj.readState == 4) {
       alert(obj.responseText)
    }
}
XMLHttpRequest를 지원하고 있는 브라우저

윈도우판 IE, 맥 safari, 리눅스 Konqueror, 그리고 OS와 상관없이 크로스 플랫폼으로 동작하는 Firefox, Nescape, Opera가 지원하고 있는 터라, 현재 주로 쓰이고 있는 환경의 대부분이 포함되어 있다고 할 수 있는 상태이다.

  • Microsoft Internet Explorer 4.0 이후
  • Mozilla Firefox 1.0 이후
  • Nescape 7 이후(Mozilla M18:2000-10-09 이후 / 1.0:2002-05-30 이후 안정)
  • Opera 7.6 이후
  • Safari 1.2 이후
  • Konqueror 3 이후

기타 reference

  • obj.abort()
    설명 : 요청을 취소하는 메소드
  • value = getResponseHeader(header)
    설명 : 인수로 지정한 응답헤더를 돌려주는 메소드, send() 메소드가 성공한 다음에 설정됨.
    header : 검색하고 싶은 헤더 이름
  • obj.getAllResponseHeaders()
    설명 : HTTP요청에 대한 모든 응답 헤더를 돌려주는 메소드
// 수신완료 후, 모든 응답 헤더를 대화창에 표시
if (obj.readyState == 4) {
    alert(obj.getAllResponseHeaders())
}

실행 결과:

Date : Mon, 1 May 2006 14:45:24 GMT
Server : Apache/2.0.40 (Red Hat Linux)
Last-Modified: Mon, 1 May 2006 14:51:20 GMT
ETag : "6b043c-51-62002a00"
Accept=Ranges: bytes
Content-Length: 81
Keep-Alive : timeout=12, max=198
Connection: Keep-Alive
Content-Type: text/plain

4. 샘플소스

Ajax용 간이 크로스 브라우저 라이브러리를 작성하여, response에 대해 XML이나 Text형식으로 받아 처리하는 예제를 테스트해보도록 한다.

jslb-ajax.js
	////
	// 동작가능한 브라우저 판정
	//
	// @sample        if(chkAjaBrowser()){ location.href='nonajax.htm' }
	// @sample        oj = new chkAjaBrowser();if(oj.bw.safari){ /* Safari 코드 */ }
	// @return        라이브러리가 동작가능한 브라우저만 true  true|false
	//
	function chkAjaBrowser()
	{
		var a,ua = navigator.userAgent;
		this.bw= { 
		  safari    : ((a=ua.split('AppleWebKit/')[1])?a.split('(')[0]:0)>=124 ,
		  konqueror : ((a=ua.split('Konqueror/')[1])?a.split(';')[0]:0)>=3.3 ,
		  mozes     : ((a=ua.split('Gecko/')[1])?a.split(" ")[0]:0) >= 20011128 ,
		  opera     : (!!window.opera) && ((typeof XMLHttpRequest)=='function') ,
		  msie      : (!!window.ActiveXObject)?(!!createHttpRequest()):false 
		}
		return (this.bw.safari||this.bw.konqueror||this.bw.mozes||this.bw.opera||this.bw.msie)
	}
	

	////
	// XMLHttpRequest 오브젝트 생성
	//
	// @sample        oj = createHttpRequest()
	// @return        XMLHttpRequest 오브젝트(인스턴스)
	//
	function createHttpRequest()
	{
		if(window.ActiveXObject){
			 //Win e4,e5,e6용
			try {
				return new ActiveXObject("Msxml2.XMLHTTP") ;
			} catch (e) {
				try {
					return new ActiveXObject("Microsoft.XMLHTTP") ;
				} catch (e2) {
					return null ;
	 			}
	 		}
		} else if(window.XMLHttpRequest){
			 //Win Mac Linux m1,f1,o8 Mac s1 Linux k3용
			return new XMLHttpRequest() ;
		} else {
			return null ;
		}
	}
	
	////
	// 송수신 함수
	//
	// @sample         sendRequest(onloaded,'&prog=1','POST','./about2.php',true,true)
	// @param callback 송수신시에 기동하는 함수 이름
	// @param data	   송신하는 데이터 (&이름1=값1&이름2=값2...)
	// @param method   "POST" 또는 "GET"
	// @param url      요청하는 파일의 URL
	// @param async	   비동기라면 true 동기라면 false
	// @param sload	   수퍼 로드 true로 강제、생략또는 false는 기본
	// @param user	   인증 페이지용 사용자 이름
	// @param password 인증 페이지용 암호
	//
	function sendRequest(callback,data,method,url,async,sload,user,password)
	{
		//XMLHttpRequest 오브젝트 생성
		var oj = createHttpRequest();
		if( oj == null ) return null;
		
		//강제 로드의 설정
		var sload = (!!sendRequest.arguments[5])?sload:false;
		if(sload || method.toUpperCase() == 'GET')url += "?";
		if(sload)url=url+"t="+(new Date()).getTime();
		
		//브라우저 판정
		var bwoj = new chkAjaBrowser();
		var opera	  = bwoj.bw.opera;
		var safari	  = bwoj.bw.safari;
		var konqueror = bwoj.bw.konqueror;
		var mozes	  = bwoj.bw.mozes ;

		//송신 처리
		//opera는 onreadystatechange에 중복 응답이 있을 수 있어 onload가 안전
		//Moz,FireFox는 oj.readyState==3에서도 수신하므로 보통은 onload가 안전
		//Win ie에서는 onload가 동작하지 않는다
		//Konqueror은 onload가 불안정
		//참고 http://jsgt.org/ajax/ref/test/response/responsetext/try1.php
		if(opera || safari || mozes){
			oj.onload = function () { callback(oj); }
		} else {
		
			oj.onreadystatechange =function () 
			{
				if ( oj.readyState == 4 ){
					callback(oj);
				}
			}
		}

		//URL 인코딩
		data = uriEncode(data)
		if(method.toUpperCase() == 'GET') {
			url += data
		}
		
		//open 메소드
		oj.open(method,url,async,user,password);

		//헤더 application/x-www-form-urlencoded 설정
		setEncHeader(oj)

		//디버그
		//alert("////jslb_ajaxxx.js//// \n data:"+data+" \n method:"+method+" \n url:"+url+" \n async:"+async);
		
		//send 메소드
		oj.send(data);

		//URI 인코딩 헤더 설정
		function setEncHeader(oj){
	
			//헤더 application/x-www-form-urlencoded 설정
			// @see  http://www.asahi-net.or.jp/~sd5a-ucd/rec-html401j/interact/forms.html#h-17.13.3
			// @see  #h-17.3
			//   ( enctype의 기본값은 "application/x-www-form-urlencoded")
			//   h-17.3에 의해、POST/GET 상관없이 설정
			//   POST에서 "multipart/form-data"을 설정할 필요가 있는 경우에는 커스터마이즈 해주세요.
			//
			//  이 메소드가 Win Opera8.0에서 에러가 나므로 분기(8.01은 OK)
			var contentTypeUrlenc = 'application/x-www-form-urlencoded; charset=UTF-8';
			if(!window.opera){
				oj.setRequestHeader('Content-Type',contentTypeUrlenc);
			} else {
				if((typeof oj.setRequestHeader) == 'function')
					oj.setRequestHeader('Content-Type',contentTypeUrlenc);
			}	
			return oj
		}

		//URL 인코딩
		function uriEncode(data){

			if(data!=""){
				//&와=로 일단 분해해서 encode
				var encdata = '';
				var datas = data.split('&');
				for(i=1;i<datas.length;i++)
				{
					var dataq = datas[i].split('=');
					encdata += '&'+encodeURIComponent(dataq[0])+'='+encodeURIComponent(dataq[1]);
				}
			} else {
				encdata = "";
			}
			return encdata;
		}


		return oj
	}
  • XML을 동적 수신
    XmlSample.htm
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <TITLE>AJAX</TITLE>
    <!-- Ajax간이 라이브러리 jslb_ajax.js -->
    <script languege = "JavaScript" src = "../../lib/jslb_ajax.js" charset = "utf-8"></script>
    <script language = "JavaScript">
    <!--
    
      //콜백 함수 ( 수신시에 실행됩니다 )
      function on_loaded1(oj)
      {
          //응답을 취득
          var xmlDoc  = oj.responseXML
          //testdata 태그를 배열로 잡는다
          var nodes = xmlDoc.getElementsByTagName("testdata")
          //최초의 testdata  태그의 firstChild의 값을 표시한다
          alert(nodes[0].firstChild.nodeValue)
      }
      
    //-->
    </script>
    
    <form>
      <input type    = "button"
             value   = "test.xml를 읽어 들여, 대화창에 표시합니다"
             onclick = "sendRequest(on_loaded1,'','GET','./test.xml',true,true)">
    </form>
    
    test.xml(UTF-8)
    <?xml version="1.0" encoding="UTF-8"?>
    <testdata>XML을 읽어 들입니다</testdata>
    
  • Text를 동적 수신
    TextSample.htm
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <TITLE>AJAX</TITLE>
    
    <!-- Ajax간이 라이브러리 jslb_ajax.js -->
    <script languege = "JavaScript"
            src      = "./lib/jslb_ajax.js"
            charset  = "utf-8"></script>
    
    <script language = "JavaScript">
    <!--
    
      //콜백 함수 ( 수신시에 실행됩니다 )
      function on_loaded1(oj)
      {
        //응답을 취득하여 디코딩
        var res  = decodeURIComponent(oj.responseText)
        
        //응답된 문자열을 대화창에 표시
        alert(res)
      }
    
    //-->
    </script>
    
    <form>
      <input type    = "button"
             value   = "test.txt을 읽어들여, 대화창에 표시합니다"
             onclick = "sendRequest(on_loaded1,'','GET','./test.txt',true,true)">
    </form>
    
    test.txt(UTF-8)
    이제 읽어들였습니다.
    

5. 활용예제

  • 글자자동완성 기능(Naver등 각종 포탈, Google Suggest) - Ajax를 위한 별도의 DB를 구성하기도 함.

  • Google Map
  • Gmail
  • Flickr
  • Amazon's A9.com
  • Ajax를 이용한 RSS Reader

관련링크 & 참고문서

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. 4월 23, 2006

    강윤기 says:

    8차 스터디 파트너 최진영씨 연락이 안되서요~ ~ 우선 젤루 쉬워 보이는걸루 선택했습니다. ^^ 잘써야할텐데

    8차 스터디 파트너 최진영씨 연락이 안되서요~
    ~ 우선 젤루 쉬워 보이는걸루 선택했습니다. ^^ 잘써야할텐데

  2. 5월 03, 2006

    고덕성 says:

    고생이 많으시군요 ^^. 이따 뵙겠습니다. ~

    고생이 많으시군요 ^^. 이따 뵙겠습니다. ~

  3. 5월 03, 2006

    최진영 says:

    하핫~ 넘 늦어서 지성~ ^^;;

    하핫~ 넘 늦어서 지성~ ^^;;

  4. 5월 04, 2006

    남연숙 says:

    어제 못가서 .. 죄송해요. ajax 꼭 듣구 싶었던 내용이였는데.. 회사에 오픈하는게 있어서 참석하지못했네요~

    어제 못가서 .. 죄송해요.
    ajax 꼭 듣구 싶었던 내용이였는데..
    회사에 오픈하는게 있어서 참석하지못했네요~

  5. 4월 02, 2007

    Nara park says:

    샘플코드 테스트 결과 IE7에서 responseXML 테스트는 htm파일과 xml파일을 charset을 utf-8으로 하면 JS 에러가 발생...

    샘플코드 테스트 결과 IE7에서

    responseXML 테스트는 htm파일과 xml파일을 charset을 utf-8으로 하면 JS 에러가 발생하네요
    charset을 euc-kr로 변경하면 정상적으로 작동하구요.
    한글 IE7이라서 그런건지...아니면.. ^^;

    responseText 테스트는 정상적으로 작동하네요.

    타 브라우저 테스트는 FireFox에서 해봤는데..
    정상작동하구요.