소개

현대적인 웹 애플리케이션은 전부 다양한 Ajax 관련 개념을 바탕으로 한다. Ajax 기술의 사용은 웹 페이지에서 대화식 또는 동적 인터페이스의 증가로 이어졌다. Ajax 혁명은 웹 애플리케이션이 백그라운드에서 비동기 방식으로 서버에서 데이터를 검색할 수 있고, 웹 페이지와 서버 간의 상호 작용이 페이지가 페치되는 순간으로 제한되지 않는다는 개념에서 비롯되었다. 웹 페이지 개념은 애플리케이션의 백엔드와 지속적으로 통신함으로써 사용자와 상호 작용하는 수명이 긴 웹 애플리케이션으로 확장되었다. 이런 지속적인 통신에서 고려하는 사항을 몇 가지 예로 들면 다음과 같다.

My developerWorks의 Web development 그룹에 참여하기

My developerWorks Web development 그룹에서 다른 개발자와 함께 웹 개발에 대해 논의하고 리소스를 공유하자.

  • 정보 송수신
  • 임시 입력 유효성 검증(예: 비밀번호 보안 수준)
  • 서버에서 수행되는 분석과 규칙을 바탕으로 한 사용자 입력 자동 완성

클라이언트와 서버 간의 상호 작용과 관련된 작업을 수행하려면 애플리케이션에 각각의 통신 작업에 알맞은 통신 메커니즘을 제공하는 최적의 통신 계층이 필요하다.

이 기사에서는 통신 계층을 생성할 때 고려할 문제에 대해 살펴보고 이 계층에 빌드해야 하는 다양한 메커니즘에 대해 학습한다.


옛 방식대로 작업

과거에는 웹 페이지와 서버 간의 통신이 해킹으로 간주되었다. 서로 다른 HTML 요소를 사용할 의도가 없는 방식으로 이들을 사용해야만 이런 통신이 가능했다. 이런 요소들의 사용(또는 남용)을 고려한 이들 요소의 주요 특징은 서버에서 파일을 페치하는 것을 목적으로 한다는 점이다. 그래서 브라우저는 요소의 유형을 바탕으로 파일을 해석하는 역할을 한다. 이들 요소는 다음과 같다.

img
이미지 파일 페치
script
JavaScript™ 파일 페치
iframe
HTML 파일을 표시하며 페치도 가능

이들 요소의 목적은 웹 사이트의 마크업을 구성하는 것이다. 또한, JavaScript를 사용하여 DOM을 조작함으로써 동적인 방식으로 요소를 주입하고 페이지 라이프사이클의 일부로서 서버와 상호 작용할 수 있다. 다음 세 섹션에서 이들 요소의 사용 방법을 설명한다.


실행 후 망각: <img> 요소의 남용

img 요소의 주 용도는 서버에서 이미지를 페치하여 표시하는 것이다. 이미지를 페치하기 위해, 브라우저에서는 이 요소의 src 속성 값인 URL을 이용해 GET 요청을 만든다. 이 값은 브라우저의 "동일 출처 정책(same origin policy)"에 따른 제한을 받지 않으므로, 이미지의 URL은 그 이미지를 표시하는 페이지의 도메인으로 제한되지 않는다.

할 수 있는 일과 할 수 없는 일

img 요소를 사용하여 어떤 URL에서든 GET 호출을 수행하는 것은 가능하다. 그런 다음, 논리적으로는 다른 서버 상의 서비스를 호출할 수 있다.

캐싱에 주의

브라우저나 임의의 네트워크 노드에서 도중에 GET 호출을 캐시할 수 있다는 점을 기억하자. <img> 요소를 사용하여 호출하는 경우 (예를 들어, 임의의 URL 매개변수를 추가하여) 캐시할 수 없는 URL을 작성해야 할 수도 있다.

하지만, 브라우저에서는 그 GET 호출에 대한 응답이 이미지 파일이며 (화면에 해당 이미지 파일을 표시함으로써) 이 응답에서 그렇게 처리하는 것으로 가정한다. 응답이 사실은 이미지 파일이 아닌 경우에는, (img 요소가 페이지에 추가되었는지 여부와는 상관없이) src 속성이 설정될 때 GET 요청이 만들어지기 때문에 단순히 img 요소를 DOM 트리에 추가하지 않으면 된다.

서버에서 리턴하는 응답이 클라이언트에게는 관심의 대상이 아닌 "실행 후 망각(fire-and-forget)"하는 서비스 유형에 주로 이 img 요소를 사용할 수 있다. 이 요소는 "서버에서 일어나는 일은 서버 내에서만 머문다"는 규칙을 따르는 서비스에 적합하다.

Listing 1은 실행 후 망각하는 호출을 수행하는 방법을 나타낸 것이다.


Listing 1. 실행 후 망각하는 방식으로 서비스 호출
                
<script type=”text/javascript”>
function fireAndForgetService(targetUrl){
  // first we create an img object
  var imgNode = document.createElement(“img”);
  // then we set its src attribute to the url of the service we’d like to invoke
  // when the next code line is executed the browser creates a GET request
  // and sends it to targetURL
  imgNode.src = targetUrl;
  
}
// calling the function with any url – cross site scripting is possible here
  fireAndForgetService(“http://www.theTargetUrl.com/doSomething?param1Name:param1Value”);
</script>
            


페치 및 실행: <script> 요소 사용

script 요소를 대신 사용하는 경우 img 요소에 대해 앞서 언급한 거의 모든 것이 동일하게 작동한다. 이 통신 메커니즘 역시 브라우저의 "동일 출처 정책(same origin policy)"에 따른 제한을 받지 않는다.

그러나 <img> 및 <script> 요소의 한 가지 다른 점은 script 요소를 사용할 때 브라우저에서 실행 가능한 JavaScript 코드를 받을 것으로 예상한다는 점이다. 이것은 가볍게 사용해서는 안 되는 매우 강력한 메커니즘이다. 페치된 스크립트가 호출되면 쿠키, DOM, 히스토리 등을 포함하여 페이지에서 액세스할 수 있는 모든 것에 호출된 스크립트가 액세스할 수 있다.

할 수 있는 일과 할 수 없는 일

브라우저에서 실행되는 코드와 페치된 스크립트 사이에서 프로토콜을 정의해야 한다. 자신의 도메인에서 스크립트를 페치하는 경우에는 이 코드가 다양한 함수, 유틸리티 및 애플리케이션 코드의 제한조건에 익숙할 것이다. 이 프로토콜은 기본적으로 동일한 애플리케이션의 두 컴포넌트 간에 이루어지는 상호 작용일 수 있다. 서버는 브라우저에서 실행해야 하고 국제화 제한 사항이나 다른 사용자별 적응을 처리하는 것과 같이 브라우저에서 다양한 조작을 할 수도 있는 코드의 일부를 요청의 일부로서 수신할 수 있다.

JSON

JSON(JavaScript Object Notation)은 JavaScript 오브젝트를 설명하기 위한 한 가지 방법이다. 이것은 매우 강력한 데이터 형식으로서, 브라우저에서 JavaScript 오브젝트로 신속히 변환할 수 있다. 참고자료를 통해 JSON에 대한 자세한 내용을 확인할 수 있다.

다른 서버에서 코드를 페치해야 할 때 더욱 흥미로워진다. 이 경우와 해당 도메인을 신뢰할 만한 경우, 페치된 스크립트는 애플리케이션 생성에 어울리지 않으므로 정적 데이터만 페치할 수 있다. 애플리케이션에서 이 데이터를 처리하려면 어떻게 해서든지 페치된 내용을 애플리케이션의 코드와 통합해야 한다. 페치된 코드가 JSON 오브젝트를 허용하는 함수 호출로 랩핑되거나 채워진 JSON 오브젝트임을 기본적으로 제시하는 JSONP 개념을 사용할 수 있다. (이런 호출을 콜백이라고 한다.) 그 함수의 이름은 페치된 스크립트의 URL 중 일부인 URL 매개변수로 전송되고, 이는 그 함수의 이름으로 랩핑된 JSON 오브젝트를 제공하는 것은 받는 사람의 도메인에 달렸다.

Listing 2는 JSONP를 바탕으로 클라이언트와 서버 간의 통신을 수행하는 방법을 나타낸 것이다.


Listing 2. JSONP 접근 방식
<script type=”text/javascript”>
// the next function receives the following arguments:
// targetUrl – the url from which data is fetched and handled later as 
//             jsonp
// jsonpName – the name of the url parameter that the target url accepts and
//             knows to read from the callback name 
// callbackName – the name of the function that will handle the returned
//             json object
function invokeJSONP(targetUrl, jsonpName ,callbackName){
  // first we create a script object
  var scriptNode = document.createElement(“script”);
  // set its type so upon return it would be executed
  scriptNode.type = “text/javascript”;
  // set its src attribute to the url of the fetched script
  // and add to the url the callback name 
  scriptNode.src = targetUrl+”?”+ targetDomainJsonpName+”=”+callbackName;
  // adding the script to the page to get it up and running
  document.getElementsByTagName(“head”)[0].appendChild(scriptNode);
  
}
// calling the function with any url – cross site scripting is possible here

function handleJsonp(infoObject){
  validateInfoObject(infoObject);
  handleInfoObject(infoObject);
}

  invokeJSONP (“http://targetUrl.com/provideJsonpData”,“jsonpCallback”, “handleJsonp”);
</script>  

한 가지 작은 차이점을 언급할 필요가 있겠다. <img> 요소를 사용할 때는 DOM 트리에 이 요소를 추가할 필요가 없다. 이와는 반대로, 스크립트 페치를 실행할 때는 <script> 요소를 DOM 트리에 추가하지 않으면 GET 요청이 생성되지 않는다.

JSONP 호출을 위한 API, 특히 콜백 이름을 제공해야 하는 애플리케이션에 있는 매개변수 이름을 게시하는 것은 대상 도메인에 달렸다. API의 다른 부분에는 응답 본문으로 전송되는 JSON 오브젝트의 구조가 포함되어야 한다.

Listing 2에서 대상 도메인은 jsonpCallback(다른 도메인에서는 이름이 바뀔 수 있음)이라는 URL 매개변수를 받아들이는데, 이때 도메인에서 handleJsonp에 대한 호출인 스크립트를 리턴할 것으로 예상한다. 이 스크립트는 Listing 3과 같은 내용일 것이다.


Listing 3. JSONP가 대상 도메인에서 리턴될 때의 내용
handleJsonp( {
  ‘height’:185,
  ‘units’:’cm’,
  ‘age’: 30,
  ‘favoriteFruit’:’apple’,
  ‘likesDogs’: true
  }
  );


미들맨에게 도움 요청: <iframe> 요소 사용

iframe은 페이지 내에 페이지를 임베드할 수 있게 해주는 요소이다. 두 개의 페이지가 같은 도메인에 있었던 경우 이 두 페이지는 서로 통신하며 정보를 전송할 수 있다.

Ajax 애플리케이션에서는 이런 패러다임을 바탕으로 기본 페이지에 있는 iframe 요소를 사용하여 사용자 상호 작용과 클라이언트 및 서버 간 통신의 역할을 분리하는 것이 일반적이다. 이 요소는 사용자가 볼 수 없게 숨겨지므로, 애플리케이션의 사용자 상호 작용 활동을 전혀 방해하지 않는다.

이런 공동 작업을 통해 서버에서 어떤 종류의 내용이라도 가져올 수 있고 페이지를 새로 고치지 않고 양식을 제출할 수 있으며—모든 것은 사용자가 알지 못하게 자동으로 이루어진다.

할 수 있는 일과 할 수 없는 일

모든 요소가 페이지를 구성하는 이전의 메커니즘과는 달리, iframe 요소는 그 자체로 하나의 페이지이다. 이 요소는 특정한 종류의 내용(예: 이미지)이나 프로세스(수신한 내용의 실행)에 제한되지 않는다. 따라서 어떤 서버에서 어떤 종류의 데이터라도 검색하거나 서버로 데이터를 전송할 수 있다. 그리고 어떤 내용이라도 수신 가능하기 때문에 가능한 모든 형식을 가진 데이터를 바탕으로 상호 작용을 수행할 수 있어, 서버 측에서의 유연성이 향상된다. 양식 제출을 바탕으로 서버로 데이터를 보낼 수 있다. 또한, GET 외에도 POST 요청을 사용할 수 있다. 여러 파트로 구성된 요청이 가능하므로, 클라이언트 시스템의 파일을 서버로 업로드할 수 있다. (페이지를 새로 고치면 항상 사용자와의 나머지 상호 작용이 중단된다는 점에 주의한다.)

iframe을 사용하는 것이 완전 무결한 방법은 아니다. 사이트 상호 간의 호출이 유효하기 때문에, 애플리케이션의 보안이 취약해질 수 있다. 그 밖에도, 이 메커니즘을 바탕으로 한 모든 상호 작용이 페이지의 히스토리 오브젝트로 푸시되므로, 뒤로/앞으로 동작으로 탐색하는 사용자에게 혼란을 줄 수 있다.

iframe 사용

iframe 숨기기

iframe을 숨길 수 있는 여러 가지 방법이 있는데, 이 요소를 화면 바깥에 배치하는 방법부터 크기를 0으로 줄이는 방법까지 거의 모든 방법을 쓸 수 있다. 표시 스타일을 숨기기로 설정할 수도 있다.

하지만, 표시 스타일을 없음으로 설정할 수는 없다. 만약 이렇게 설정하면 GET 요청을 만들 수 없고 서버에서 필요한 내용을 페치할 수 없다.

iframe 요소를 사용하여 프로그램을 통한 방법으로 서버에서 내용을 페치하는 것은 script 요소를 사용하는 것과 비슷하지만,—한 가지 중요한 차이점이 있다. script 요소를 만들어 페이지에 연결한 후, 사용자가 화면에 이 요소가 표시됨으로써 혼동하지 않도록 이 요소를 숨겨야 한다는 점이다.

iframe 요소를 양식 제출의 대상으로 사용할 수 있으므로, 양식 제출로 인한 페이지 새로 고침을 예방할 수 있다.

Listing 4는 프로그램 방식으로 클라이언트와 서버 간 통신을 수행하는 대신 iframe 요소를 애플리케이션 마크업의 일부로 사용하여 파일을 업로드하는 방법을 나타낸 것이다.


Listing 4. <iframe>을 이용한 파일 업로드
<!—a hidden iframe that is the target of the form that would be used to upload a file -->
	 
<iframe id="IFrame" name="IFrame"
	  style="width:0px; height:0px; border:0px"
	  src="blank.html">
</iframe>

<!—the form is connected to the previous iframe by the target attribute, thus basically 
reloading that hidden frame upon form submission -->

<form name="UploadFile"  target="IFrame" method="POST"
    action="http://myServer/fileUploadServiceURL"
    enctype="multipart/form-data">
<input type="file" name="uploadFileNameId"/>
<input type="submit" value="Upload" name="submit"/>
</form>


Ajax 방식으로 작업하는 방법

Ajax 기반 웹 애플리케이션은 보통 서버에서 작동하는 애플리케이션에 대한 클라이언트 역할을 하므로, 그 서버로 데이터를 앞뒤로 보내며 통신 기능을 집중적으로 사용하는 애플리케이션이 되는 결과를 낳는다. 데이터 전송 기능을 제공할 메커니즘이 필요하다. 애플리케이션의 주요 컴포넌트로서, 이런 메커니즘은 최대한 가볍고 안전해야 한다. 다행히도, 모든 현대적 브라우저에는 정확히 이런 목적으로 사용할 수 있는 오브젝트, 즉 XHR(XMLHttpRequest)이 갖춰져 있다. 실제로 가벼운 XHR은 페이지를 검색한 서버로 한정되는 요청을 생성한다. XHR은 사이트 간 스크립팅 문제를 제거하며, 텍스트만 전달할 수 있다.

할 수 있는 일과 할 수 없는 일

애플리케이션은 XHR 오브젝트를 사용하여 서버로 정보를 보내고 서버에서 데이터를 페치할 수 있다. 이 메커니즘은 앞서 설명한 메커니즘에 비해 여러 가지 장점이 있다.

어떤 유형의 HTTP 메소드라도 사용 가능
현재 도입된 대부분의 일반적인 서버 아키텍처는 REST 원리를 기반으로 하기 때문에, GET, PUT, POST 및 DELETE 요청을 사용해야 한다. 클라이언트와 서버 간 통신의 핵심이라 할 수 있는 XHR 오브젝트의 사용으로 RESTful 서버 아키텍처를 사용할 수 있다.
완료 시 알림
XHR 오브젝트는 생성에서부터 응답이 완전히 로드되기까지 여러 가지 상태에서 존재할 수 있다. 각각의 상태 변화 시, 이벤트가 실행되고 앞으로의 상태 변화 시 호출할 콜백을 정의할 수 있다.

이 이벤트 핸들러를 통해 서버에서 페치된 데이터에 의존하는 코드가 해당 데이터를 사용할 수 있을 때 실행되도록 할 수 있다.

페이지 히스토리에 개입 없음
XHR 호출은 페이지의 히스토리 오브젝트에 반영되지 않으므로, 브라우저의 뒤로 및 앞으로 동작의 일반적인 용도에서 벗어나지 않는다.

Cross-Origin Resource Sharing

CORS(Cross-Origin Resource Sharing) 메커니즘을 사용하면 Cross-site Ajax 호출이 가능하다. 하지만, CORS가 아직은 등장한 지 얼마 되지 않아 일부 브라우저에서만 지원되며, 서버 측에서 추가로 코딩 작업을 해야 한다.

크로스 사이트 스크립팅(XSS)이 허용되지 않음
이 애플리케이션은 XSS를 수행할 능력이 결여되어 있기 때문에 더 안전하다.
블로킹하거나 못하거나
요청-응답 주기가 다음 중 어떤 것이 될지 정의할 수 있다.
  • 동기(브라우저가 응답을 기다리는 동안 아무런 코드도 실행되지 않음)
  • 비동기(응답이 도착했을 때 콜백을 실행할 수 있음)
XML 또는 다른 모든 형식
응답이 XML 형식으로 되어 있는 경우, 그 응답 데이터에 대해 완전한 DOM 트리가 만들어진다. 응답의 원시 텍스트 내용도 사용 가능하고, 응답이 JSON과 같은 다른 형식으로 도착할 때 이를 처리할 수 있다.

그래도 XHR 오브젝트와 관련된 모든 것이 좋은 면만 있는 것은 아니다. 텍스트만 보낼 수 있기 때문에, 여전히 iframe을 사용하여 파일을 서버에 업로드해야 한다. 그 밖에도, 다른 브라우저에서는 이 오브젝트의 작성이 다른 방법으로 이루어진다.


요약

클라이언트와 서버의 상호 작용은 모든 현대적 웹 애플리케이션의 중추이다. 이 기사에서는 애플리케이션 상호 작용을 위해 사용할 수 있는 공통의 메커니즘에 대해 학습했다. 이 기사에서 설명한 모든 메커니즘이 모든 애플리케이션에서 필요한 것은 아니다. 어떤 메커니즘이 필요하고 어떻게 사용할지 결정하는 것은 개발자의 몫이다.

수많은 JavaScript 프레임워크에 Ajax 통신 메커니즘 세트가 부분적이거나 완전하게 구현되어 있다. 어떤 프레임워크를 사용하고 어떤 메커니즘을 구현할지 결정할 때 이 점을 고려한다.

2011/09/14 01:59 2011/09/14 01:59

Trackback Address :: 이 글에는 트랙백을 보낼 수 없습니다