XMLHTTP를 사용한 동적 페이지 업데이트

기술 자료 번역 기술 자료 번역
기술 자료: 893659 - 이 문서가 적용되는 제품 보기.
ASP.NET Support Voice 칼럼

XMLHTTP를 사용한 동적 페이지 업데이트

사용자의 필요에 맞는 칼럼을 게시할 수 있도록 향후 기술 자료 문서 및 Support Voice 칼럼에서 다루었으면 하는 문제와 관심 있는 항목에 대한 의견을 보내주시기 바랍니다. 요청(Ask For It) 양식을 사용하여 의견이나 피드백을 보낼 수 있습니다. 이 칼럼 하단에도 이 양식에 대한 링크가 제공됩니다.
모두 확대 | 모두 축소

이 페이지에서

소개

웹 응용 프로그램의 사용 편의성을 연구하는 방법 중 주로 사용하는 방법은 제 와이프의 웹 사이트 탐색을 지켜보는 것입니다. 그녀는 나름으로 인터넷을 잘 사용하지만 그 모든 것을 가능하게 하는 하위 수준의 기술적 측면 즉, 그녀가 "지루한 것"이라 부르는 내용들에 대해서는 거의 알지 못합니다.

며칠 전 저녁에 제 와이프가 한 대기업으로부터 받은 전자 상거래 응용 프로그램을 자세히 살피고 있더군요. 여러 개의 드롭다운을 사용하여 제품 목록을 표시하고 해당 드롭다운들은 이전에 선택한 항목으로 채워지고 있었구요. 각 드롭다운에서 항목을 선택한 순간 다음 드롭다운의 데이터를 가져오기 위해 페이지가 다시 게시되었습니다. 여러 번 다시 게시되는 문제 때문에 시간이 오래 걸린다면서 좀 불편해 하더라구요.

응용 프로그램 개발자들이 데이터를 가져오는 방법으로 페이지를 다시 게시하는 대신 XMLHTTP를 사용했었다면 그녀가 겪은 불편함은 쉽게 사라졌을 것입니다. 이달의 칼럼 내용이 바로 이것입니다. 저는 XMLHTTP를 사용하여 다시 게시하지 않고도 Microsoft ASP.NET 웹 서비스의 데이터로 웹 페이지를 업데이트하는 방법에 대해 설명하겠습니다. 정말 멋지겠지 않습니까! 자, 시작해 볼까요?

일반 개요

XMLHTTP는 클라이언트로부터 웹 서버로 요청을 보내고 XML 데이터 아일랜드를 반환하는 방식으로 작동합니다. 받은 XML의 구조에 따라 XSLT 또는 XML DOM을 사용하여 페이지를 조작하고 페이지의 일부를 해당 데이터에 바인딩합니다. 이 기술은 매우 강력한 기술입니다.

참고?Microsoft는 ASP.NET 웹 서비스에 대한 비동기 호출을 빠르고 간편하게 수행하도록 Internet Explorer에 웹 서비스 동작을 제공합니다. 하지만 이 동작은 지원되지 않으며 페이지를 비동기적으로 업데이트하는 것이 최선은 아닙니다. 대신 XMLHTTP를 사용해야 합니다.

이 칼럼에 나와 있는 예제에서는 XMLHTTP를 통해 ASP.NET 웹 서비스에 대한 세 가지 웹 서비스 호출을 수행합니다. 웹 서비스는 로컬 SQL Server의 Northwind 데이터베이스를 쿼리하고 XML DiffGram의 폼으로 클라이언트에게 DataSet를 반환합니다. XML DOM을 사용하여 해당 XML 데이터를 구문 분석하고 페이지를 동적으로 업데이트합니다. 다시 게시하지 않고도 이 모든 작업을 수행합니다.

웹 서비스

사용할 웹 서비스 이름을 DynaProducts로 지정했습니다. C#으로 쓰여진 기본 ASP.NET 웹 서비스로, 다음 세 가지 메서드가 포함되어 있습니다.
  • GetCategories ? Categories 테이블에서 모든 범주를 포함하는 DataSet를 반환합니다.
  • GetProducts ? 메서드로 전달된 모든 제품 범주를 포함하는 DataSet를 반환합니다.
  • GetProductDetails ? 메서드로 전달된 ProductID의 제품 정보를 포함하는 DataSet를 반환합니다.

HTML 페이지

이 예제를 보고 맨 처음 알 수 있는 것은 ASP.NET 웹 서비스를 통해 업데이트하는 페이지가 ASP.NET 페이지가 아니라는 것입니다. 그저 보통의 HTML 페이지일 뿐입니다. 하지만 많은 양의 클라이언트쪽 JavaScript를 페이지에 추가했고 이 스크립트는 웹 서비스에 대한 호출을 수행하는 스크립트입니다.

자, HTML 페이지의 첫 번째 코드 예제를 살펴봅시다.
var objHttp;
var objXmlDoc;

function getDataFromWS(methodName, dataSetName, wsParamValue, wsParamName)
{

    // create the XML object
    objXmlDoc = new ActiveXObject("Msxml2.DOMDocument");

    if (objXmlDoc == null)
    {
        alert("Unable to create DOM document!");
        
    } else {

	    // create an XmlHttp instance
	    objHttp = new ActiveXObject("Microsoft.XMLHTTP");
	
	
	    // Create the SOAP Envelope
	    strEnvelope = "<soap:Envelope xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
	
	            " xsd=\"http://www.w3.org/2001/XMLSchema\"" +
	
	            " soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
	
	            "  <soap:Body>" +
	
	            "    <" + methodName + " xmlns=\"http://jimcoaddins.com/DynaProducts\">" +
	
	            "    </" + methodName + ">" +
	
	            "  </soap:Body>" +
	
	            "</soap:Envelope>";
	
	
	    // Set up the post
	    objHttp.onreadystatechange = function(){
	
	        // a readyState of 4 means we're ready to use the data returned by XMLHTTP
	        if (objHttp.readyState == 4)
	        {
	
	            // get the return envelope
	            var szResponse = objHttp.responseText;
							
	            // load the return into an XML data island
	            objXmlDoc.loadXML(szResponse);
	
	            if (objXmlDoc.parseError.errorCode != 0) {
	                var xmlErr = objXmlDoc.parseError;
	                alert("You have error " + xmlErr.reason);
	            } else {
	
	                switch(dataSetName)
	                {
	                    case "CategoriesDS":
	                        processCategory();
	                        break;
	
	                    case "ProductsDS":
	                        processProducts();
	                        break;
	
	                    case "ProductDetailDS":
	                        processProductDetails();
	                        break;
	
	                }
	            }
	
	        }
	     }
	
	    var szUrl;
	    szUrl = "http://dadatop/wsXmlHttp/DynaProducts.asmx/" + methodName;
	
	    if (wsParamValue != null)
	    {
	
	        szUrl += "?" + wsParamName + "=" + wsParamValue;
	    }
	
	    // send the POST to the Web service
	    objHttp.open("POST", szUrl, true);
	    objHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	    objHttp.send(strEnvelope);
	  }
}
이 예제는 페이지에서 가장 큰 코드로서 내용을 이해할 수 있도록 코드를 자세히 설명하겠습니다.

이 스크립트 블록의 맨 위에 두 개의 변수 objHttpobjXmlDoc를 만들었습니다. 이들 변수는 XMLHTTP 개체와 XML DOM 개체에 사용할 변수입니다. 바로 뒤에 getDataFromWS 함수의 함수 정의가 있습니다. 이 함수는 웹 서비스에 대한 클라이언트쪽 호출을 담당하는 함수로, 다음 네 가지 인수를 가지며 그 중 두 가지는 선택적입니다.
  • methodName ? 웹 서비스에서 호출하는 메서드 이름
  • dataSetName ? 웹 서비스에서 반환되는 DataSet 이름
  • wsParamValue ? 해당되는 경우 웹 서비스에 전달되는 매개 변수 값(선택적)
  • wsParamName ? 해당되는 경우 웹 서비스에 전달되는 매개 변수 이름(선택적)
getDataFromWS 함수를 세분화하여 각 항목에 대해 자세히 살펴봅시다. 첫 번째 코드는 다음과 같습니다.
// create the XML object
    objXmlDoc = new ActiveXObject("Msxml2.DOMDocument");

    if (objXmlDoc == null)
    {
    		alert("Unable to create DOM document!");

    } else {

		// create an XMLHTTP instance
		objHttp = new ActiveXObject("Microsoft.XMLHTTP");
이 코드 블록은 XMLHTTP 개체와 XML Document 개체를 만듭니다. 다음에서는 SOAP 봉투를 만들기 시작합니다.
// Create the SOAP Envelope
strEnvelope = "<soap:Envelope xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
	
          " xsd=\"http://www.w3.org/2001/XMLSchema\"" +
	
          " soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
	
          "  <soap:Body>" +
	
          "    <" + methodName + " xmlns=\"http://jimcoaddins.com/DynaProducts\">" +
	
          "    </" + methodName + ">" +
	
          "  </soap:Body>" +
	
          "</soap:Envelope>";
이 코드에서는 웹 서비스에 전달할 수 있도록 문자열 변수에 SOAP 봉투를 지정합니다. 사용자 웹 서비스의 SOAP 봉투 형식을 지정하는 방법은 실제로 쉽게 찾을 수 있습니다. 간단히 웹 서비스를 탐색하고 메서드 중 하나를 클릭하여 해당 메서드의 SOAP 봉투를 확인합니다. 예를 들어 다음은 이 문서의 예제로 작성한 wsXMLHTTP 웹 서비스의 GetCategories 메서드를 탐색할 때 표시되는 모양입니다.

그림 축소그림 확대
envelope.png


ASP.NET은 SOAP 봉투의 형식을 HTTP POST로 지정해야 하는지, HTTP GET으로 지정해야 하는지에 대해 알려줍니다. 이 문서에 소개된 예제에서는 HTTP POST를 사용합니다.

지금까지는 어렵지 않죠? 자, 이제 다음 코드 섹션을 살펴봅시다.
// Set up the post
objHttp.onreadystatechange = function(){
	
// a readyState of 4	means we're ready to use the	data returned by	XMLHTTP
	if (objHttp.readyState == 4)
	{
	
		// get	the return envelope
		   var	szResponse	= objHttp.responseText;
	
		   // load	the return into an XML data island
		   objXmlDoc.loadXML(szResponse);
	
		   if (objXmlDoc.parseError.errorCode != 0) {
			var xmlErr =	objXmlDoc.parseError;
				 alert("You have error " + xmlErr.reason);
	}
	else	
	{

		switch(dataSetName)
				{
					case "CategoriesDS":
						processCategory();
						break;
					case "ProductsDS":
						processProducts();
						break;
					case "ProductDetailDS":
					processProductDetails();
						break;

				}
			}
XMLHTTP를 통해 요청이 만들어지면 XMLHTTP 개체는 readyState 속성을 사용하여 요청 상태를 추적합니다. 웹 서비스에서 모든 데이터를 다시 받은 경우 readyState 속성이 값을 4로 변경합니다. XMLHTTP 개체의 onreadystatechange 속성을 통해 readyState 속성이 변경될 때 호출되는 콜백 함수를 설정할 수 있습니다. 전체 데이터를 받았는지 확인하여 준비가 될 때까지 해당 데이터에서 작업하지 않도록 합니다.

데이터를 모두 받으면 responseText 속성을 사용하여 응답을 통해 XML 데이터 아일랜드를 만듭니다. 아시다시피 웹 서비스로부터 받은 응답은 XML 형식입니다. 이 경우에는 Microsoft ADO.NET DataSet를 반환합니다.

이 코드 블록의 다음 섹션에서는 switch 문을 사용하여 웹 서비스로부터 반환되는 DataSet 이름을 기준으로 해당 함수를 호출합니다. 이들 함수 코드에 대해서는 잠시 후에 자세히 다루겠습니다.

이제 실제로 XMLHTTP 요청을 수행하는 코드를 한 번 보시죠.
var szUrl;
	szUrl = "http://dadatop/wsXmlHttp/DynaProducts.asmx/" + methodName;
	
	if (wsParamValue != null)
	{
	
	      	szUrl += "?" + wsParamName + "=" + wsParamValue;
	}
	
// send the POST to the Web service
	objHttp.open("POST", szUrl, true);
	objHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	objHttp.send(strEnvelope);
szUrl 변수에는 확실히 하기 위하여 웹 서비스를 호출하는 데 사용되는 URL이 포함되어 있습니다. 그런 다음 QueryString 값으로 전달되는 매개 변수를 지정하는 if 문을 만듭니다. 사용자 환경에서 SOAP 봉투에 매개 변수를 추가할 수 있습니다. 어떤 방법이든 모두 괜찮습니다.

다음으로 XMLHTTP 개체의 open 메서드가 호출됩니다. open 메서드의 경우 호출이 비동기적인지 여부를 지정하는 메서드, URL 및 부울 값의 처음 세 인수를 사용했습니다.
중요?여기서처럼 비동기 호출을 수행하는 경우 onreadystatechanged 속성을 통해 콜백 함수를 설정해야 합니다.

content-type의 요청 헤더를 설정한 후 이전에 만든 문자열 변수를 사용하여 SOAP 봉투로 요청을 보냅니다.

이제는 XMLHTTP 요청을 만드는 모든 코드를 살펴보겠습니다. 브라우저 인터페이스를 처리하고 웹 서비스 호출을 통해 받은 응답을 처리하는 코드를 한 번 보시죠.

먼저 페이지를 처음으로 로드할 때 호출되는 함수를 보겠습니다.
function getCategories()
{

  var func = "getDataFromWS('GetCategories', 'CategoriesDS')";
  document.all.lblCategoryDropdown.innerText = 
"Please wait while data is retrieved...";
  window.setTimeout(func, 1);

  }
이 함수에서 맨 처음 할 일은 변수를 만들어 getDataFromWS에 함수 시그니처를 저장하는 것입니다. 왜냐하면 이 함수 마지막에 window.setTimeout을 호출하여 getDataFromWS 함수를 호출할 것이기 때문입니다. 이 방법의 목적은 웹 서비스 호출이 완료될 때까지 대기하는 동안 사용자에게 해당 상태를 표시하기 위한 것입니다. DIV의 innerText를 변경하여 데이터를 검색하고 있다는 메시지를 표시합니다. 그런 다음 window.setTimeout 호출을 통해 getDataFromWS 함수의 일정을 세우고 1밀리초 후에 실행하도록 설정합니다.

웹 서비스 응답 처리

이전에는 onreadystatechanged 속성을 사용하여 콜백 함수를 구성했으며 콜백 함수에는 DataSet 이름을 기준으로 특정 함수를 호출하는 switch 문이 포함되어 있었습니다. 이 경우 이 DataSet의 이름은 CategoriesDS입니다. 따라서 processCategory 함수는 콜백 함수를 통해 호출됩니다. XML DOM을 사용하여 웹 서비스로부터 받은 응답을 구문 분석하는 방법을 보여주는 함수를 한 번 보시죠.
function processCategory()
{

  // get an XML data island with the category data
  objNodeList = objXmlDoc.getElementsByTagName("Categories");
 
  // add default value to the drop-down
  document.forms[0].drpCategory.options[0] = new Option("Select a Category", 0);

  // walk through the nodeList and populate the drop-down
  for (var i = 0; i < objNodeList.length; i++) 
  {
      var dataNodeList;
      var textNode;
      var valueNode;

      dataNodeList = objNodeList[i].childNodes;
      valueNode = dataNodeList.item(0);
      textNode = dataNodeList.item(1);

      document.forms[0].drpCategory.options[i + 1] = 
new Option(textNode.text, valueNode.text);
      document.all.lblCategoryDropdown.innerText = "Select a Category:";
      document.forms[0].drpCategory.style.visibility = "visible";
       
    }

  }
getDataFromWS 함수는 응답으로부터 objXmlDoc 개체로 XML을 로드했습니다. processCategory 함수에서 해당 XML을 가져와 구문 분석하여 Category 드롭다운을 채웁니다.

맨 처음 할 일은 XML 응답의 일부를 사용하여 IXMLDOMNodeList 개체를 만드는 것입니다. 웹 서비스 호출에서 반환하는 DataSet는 DiffGram으로 반환되며, 흥미로운 점은 해당 응답의 일부만이 DataSet에 삽입했던 DataTable의 데이터라는 것입니다. DataTable이 있는 XML 블록에서 IXMLDOMNodeList 개체를 만들어 이와 같이 할 수 있습니다.

웹 서비스 코드를 보면 제가 Categories라는 이름의 DataTable을 만들고 이를 DataSet에 추가한다는 것을 알 수 있습니다. 아래 XML 파일에서처럼 웹 서비스에서 XML이 반환되면 DataSet는 <CategoriesDS> 블록 안에 포함되며 DataTable의 각 행은 개별 <Categories> 블록에 포함됩니다.

Microsoft 다운로드 센터에서 다음 파일을 다운로드할 수 있습니다.
그림 축소그림 확대
다운로드
지금 GetCategories.xml 패키지 다운로드(영문)
그림 축소그림 확대
다운로드
지금 WSXMLHTTP.exe 패키지 다운로드(영문) Microsoft 지원 파일을 다운로드하는 방법에 대한 자세한 내용은 Microsoft 기술 자료의 다음 문서를 참조하십시오.
119591 온라인 서비스로부터 Microsoft 지원 파일을 구하는 방법
Microsoft는 파일을 게시한 날짜에 사용할 수 있는 최신의 바이러스 예방 프로그램으로 이 파일을 검사했습니다. 이 파일은 해당 파일을 무단으로 변경할 수 없는 보안이 향상된 서버에 보관됩니다.

DataTable을 포함하는 XML 블록을 가져오기 위해 다음 코드를 사용합니다.
objNodeList = objXmlDoc.getElementsByTagName("Categories");
이 코드는 각 <Categories> 노드를 포함하고 있는 IXMLDOMNodeList 개체를 반환합니다. 그런 다음 for 루프를 사용하여 해당 목록을 반복합니다.
// walk through the nodeList and populate the drop-down
  for (var i = 0; i < objNodeList.length; i++) 
  {
      var dataNodeList;
      var textNode;
      var valueNode;

      dataNodeList = objNodeList[i].childNodes;
      valueNode = dataNodeList.item(0);
      textNode = dataNodeList.item(1);

      document.forms[0].drpCategory.options[i + 1] = 
new Option(textNode.text, valueNode.text);
      document.all.lblCategoryDropdown.innerText = "Select a Category:";
      document.forms[0].drpCategory.style.visibility = "visible";
       
    }
각 <Categories> 노드에는 제가 필요로 하는 두 개 노드, <ID> 노드와 <CategoryName> 노드가 있다는 것을 이미 알고 있습니다. 따라서 맨 처음 할 일은 새로운 IXMLDOMNodeList를 만들어 현재 <Categories> 노드의 하위 노드로 채우는 것입니다.
dataNodeList = objNodeList[i].childNodes;
그런 다음 item 메서드를 사용하여 드롭다운을 채워야 하는 두 개 노드 모두를 액세스합니다. 첫 번째 노드에는 데이터베이스의 CategoryID 필드가 포함되며 두 번째 노드에는 데이터베이스의 CategoryName 필드가 포함됩니다. 새로운 Option 개체를 만들고 텍스트를 CategoryName으로 설정하고 값을 CategoryID로 설정하여 drpCategory 드롭다운에 추가합니다. 나머지 함수에서 사용되는 코드는 동일한 메서드를 사용하여 XML 응답에서 필요한 데이터를 가져와 페이지를 채웁니다.

참고?여기서는 소량의 데이터를 처리하고 있으므로 DOM을 사용하여 필요한 데이터를 가져오는 것이 가장 좋습니다. 대량의 데이터를 처리하는 경우라면 대신 XSLT를 사용할 수 있습니다.

작업 방법

이 모든 것이 어떻게 이루어져 있는지에 대해 자세히 설명했으므로 이제는 여러분 스스로가 포함된 예제 파일을 사용하여 어떻게 작업할 것인지 생각해 보시기 바랍니다.

웹 서비스 구축

ASP.NET 웹 서비스를 구축하려면 사용자 웹 서버 루트에 첨부된 웹 서비스 예제 파일의 압축을 풉니다. 그런 다음 DynaProducts.asmx의 코드를 열고 연결 문자열을 변경해야 합니다. 최소한 SA 암호를 입력해야 합니다. 변경한 후에 웹 서비스를 다시 컴파일합니다.

HTML 파일 구축

HTML 파일에는 웹 서비스에 대한 URL을 포함하는 szUrl이라는 이름의 변수가 있으며, 함수 아래쪽의 getDataFromWS 함수에서 이 변수를 찾을 수 있습니다. 위에서 구축한 웹 서비스의 URL로 해당 변수를 변경해야 합니다.

웹 서비스와 HTML 파일 모두를 구축한 후에 HTML 파일을 탐색합니다. 파일이 로드되면 웹 서비스에 대한 첫 번째 XMLHTTP 요청으로 Category 드롭다운이 채워집니다. 드롭다운이 채워지고 나면, Products 드롭다운을 채우는 다음 XMLHTTP 요청을 시작하도록 범주를 선택합니다. Products 드롭다운에서 제품을 선택하면 해당 제품에 대한 데이터로 테이블이 채워집니다.

이들 XMLHTTP를 요청하는 동안에도 페이지는 다시 게시되지 않으며, 이것이 바로 XMLHTTP 요청의 미학입니다. 또한 큰 페이지에서 이렇게 하는 경우에도 사용자가 "눈치채지" 못하게 해당 스크롤 위치를 그대로 유지합니다. XMLHTTP가 강력한 기술이라는 것은 의심할 여지가 없지요!

한 가지 더, 이 문서에서는 XMLHTTP를 사용하여 웹 서비스를 쿼리했습니다. ASPX 페이지나 ASP 페에지에 대한 요청을 만드는 데도 매우 간편하게 사용할 수 있었습니다. 이 기술을 활용할 수 있는 방법은 무궁무진합니다. 나중에 웹 응용 프로그램을 개발할 때 XMLHTTP의 유용함을 직접 느낄 수 있기를 바랍니다.
언제라도 요청(Ask For It) 양식을 사용하여 향후 칼럼이나 Microsoft 기술 자료에서 다루었으면 하는 항목에 대한 의견을 보내주시기 바랍니다.



Microsoft 제품 관련 기술 전문가들과 온라인으로 정보를 교환하시려면 Microsoft 뉴스 그룹에 참여하시기 바랍니다.

속성

기술 자료: 893659 - 마지막 검토: 2006년 3월 15일 수요일 - 수정: 5.2
본 문서의 정보는 다음의 제품에 적용됩니다.
  • Microsoft ASP.NET 1.0
  • Microsoft ASP.NET 1.1
키워드:?
kbgraphic kbscript kbxml kbhowto KB893659

피드백 보내기

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com