RSS구독하기:SUBSCRIBE TO RSS FEED
즐겨찾기추가:ADD FAVORITE
글쓰기:POST
관리자:ADMINISTRATOR
'HTML/Ajax'에 해당되는 글 3
HTML/Ajax  2008/01/04 17:53
Content-Type은 Internt Media 타입이다. 그러나 왜 알아야 하는 가는 웹 서버 로그의 Content-Type을 보고 어떤 어플리케이션이 사용되어 있는지를 파악할 때 도움이 된다. 또한 웹 포렌식 작업을 할 때 실제 공격차단의 룰셋인지 아니면 정상적인 서비스인지의 룰인지를 판단해야 할 때 많은 도움이 될 것이다. 최근에는 웹 이외의 어플리케이션들이 HTTP+XML 형태로 사용을 많이 하기 때문에 오탐여부를 판단할 때 많은 도움이 된다.

1) Multipart Related MIME 타입
  - Content-Type : Multipart/related(기본형태)
  - Content-Type : Application/X-FixedRecord
  - Content-Type: Text/x-Okie; charset=iso-8859-1;

2) XML Media의 타입
 - Content-Type : text/xml
 - Content-Type : Application/xml
 - Content-Type : Application/xml-external-parsed-entity
 - Content-Type : Application/xml-dtd
 - Content-Type : Application/mathtml+xml
 - Content-Type : Application/xslt+xml

3) Application의 타입
 - Content-Type : Application/EDI-X12:  Defined in RFC 1767
 - Content-Type : Application/EDIFACT:  Defined in RFC 1767 
 - Content-Type : Application/javascript: Defined in RFC 4329
 - Content-Type : Application/octet-stream: <-- 디폴트 미디어 타입은 운영체제 종종 실행파일, 다운로드를 의미
 - Content-Type : Application/ogg: Defined in RFC 3534
 - Content-Type : Application/x-shockwave-flash: Adobe Flash files
 - Content-Type : Application/json: JavaScript Object Notation JSON; Defined in RFC 4627
 - Content-Type : Application/x-www-form-urlencode <-- HTML Form 형태


* x-www-form-urlencode와 multipart/form-data은 둘다 폼 형태이지만 x-www-form-urlencode은 대용량 바이너리 테이터를 전송하기에 비능률적이기 때문에 대부분 첨부파일은 multipart/form-data를 사용하게 된다.

4) 오디오 타입
- Content-Type : Type audio: Audio
- Content-Type : audio/mpeg: MP3 or other MPEG audio
- Content-Type : audio/x-ms-wma: Windows Media Audio;
- Content-Type : audio/vnd.rn-realaudio: RealAudio;  등등
 

5) Multipart 타입(아카이브 또는 개체)
- Content-Type : multipart/mixed: MIME E-mail;
- Content-Type : multipart/alternative: MIME E-mail;
- Content-Type : multipart/related: MIME E-mail; Defined in RFC 2387 and used by MHTML(HTML mail)
- Content-Type : multipart/formed-data : <-- 파일 첨부

6) TEXT 타입
- Content-Type : text/css
- Content-Type : text/html:
- Content-Type : text/javascript 
- Content-Type : text/plain:
- Content-Type : text/xml:


7) 기타 MIMERPC 예제들
가) HTTP with x/www-form-urlencoded 일반요청
POST /some/resource HTTP/1.1
Content-type: application/x-www-form-urlencoded
0=example.getStateName&1=10023


[응답]
HTTP/1.1 200 OK
Content-type: text/plain
New York


나) HTTP x/www-form-urlencoded namedArgs getTeam
POST /some/resource HTTP/1.1
Content-type: application/x-www-form-urlencoded
0=example.getTeam&state=New York&sport=Baseball


[응답]
HTTP/1.1 200 OK
Content-type: multipart/mixed, boundary=B
--BYankees

--BMets

--B


다) HTTP x/www-form-urlencoded unicode addUser
POST /some/resource HTTP/1.1
Content-type: application/x-www-form-urlencoded
0=example.addUser&fname=Igna%ACio&lname=Sanchez


라) HTTP with multipart/form-data 요청
POST /some/resource HTTP/1.1
Content-type: multipart/form-data, boundary=AaB03x
--AaB03x
content-disposition: form-data; name="field1"


Joe Blow


--AaB03x 
content-disposition: form-data; name="pics"; filename="file1.gif"
Content-type: image/gif
Content-Transfer-Encoding: binary
...contents of file1.gif...


--AaB03x--

[응답]
HTTP/1.0 200 OK
Content-type: text/plain
OK


마) Uploading multiple files with unicode

POST /foo HTTP/1.0
Content-type: multipart/form-data, boundary=AaB03x


--AaB03x
content-disposition: form-data; name="field1"
Joe Blow


--AaB03x  <-- 여러개의 파일을 첨부할 때
content-disposition: form-data; name="pics"
Content-type: multipart/mixed, boundary=BbC04y

--BbC04y  <-- 첫번째 첨부파일은 텍스트
Content-disposition: attachment; filename="file1.txt"
Content-Type: text/plain; charset=UNICODE-1-1
Content-Transfer-Encoding: binary
... contents of some unicode file.txt ...


--BbC04y <-- 두번째 첨부파일은 이미지
Content-disposition: attachment; filename="file2.gif"
Content-type: image/gifContent-Transfer-Encoding: binary
...contents of file2.gif...

--BbC04y


----AaB03x--


바) XML and EMail 요청
HTP Request
POST /x/foo/bar HTTP/1.0
reply-to-url: callback@domain.com
message-id: abc123
aynch: required0=getAuthorization&1="bobjones"


[응답]
HTTP/1.0 200 OK
delivered-to: callback@domain.com
Content-length: 0
Mail/SMTP Response
To: callback@domain.comFrom: mimeRPC@otherplace.com
in-reply-to: abc123
content-type: text/xml
<?xml version="1.0"?><this><is /><xml /></this>

또한 간혹 Content-Type외에 x-vermeer-content-type 형태가 추가로 나오는 경우가 있는데 이것은 RPC 통신을 사용하는 것을 의미하며, 마이크로소프트 제품중에 SharePoint 서버 제품군과 프론트페이지가 이 x-vermeer-Content-Type를 사용하기 때문에 기억해 두기 바란다.

2008/01/04 17:53 2008/01/04 17:53
이 글에는 트랙백을 보낼 수 없습니다

예전부터 궁금했던 cross-domain 의 한계를 극복하는 방법을 찾았습니다. 2005년 자료이지만 근본적으로는 상관 없을듯  합니다. 원문의 내용을 나름 번역을 하였는데 최대한 빠르게 번역을 해보고자 하였기 때문에 어색한 부분이 많습니다. 그런 부분은 원문에 직접 가서 보는게 좋겠습니다.

원문 : http://fettig.net/weblog/2005/11/28/how-to-make-xmlhttprequest-connections-to-another-server-in-your-domain/

Updates to this post

이 기술문서의 업데이트된 버전(firefox 1.5에서 작업한)을 여기에서 볼 수 있다.

The problem

XmlHttpRequest(이하 XHR) 객체는  다른 서버의 데이터 접근으로부터 해당 데이터를 보호하기 위해 브라우저의 same origin security policy으로 둘러싸여져 있다. 이것은 Ajax 개발자에게 심각한 한계에 부딪히게 한다: 당신은 뒷단에서 server에 호출하기 위해 XHR을 사용할수 있을 것이다. 하지만 그것은 현재 페이지와 같은 서버에서 진행되어야만 한다. 이러한 한계점을 해결할수 있는 대안으로 알려진 것으로는 server-side reverse proxyingbypassing XmlHttpRequest entirely이 있다. 나의(원문 필자)의 경우 이러한 접근들 어느쪽도 실무와 연결되지 않았다. 나는 LivePage  (Divmod에서 Donovan Preston 과 다른 훌륭한 해커들에 의해 개발되어진 live-update 프래임워크)를 사용하길 원했다. LivePage는 동시에 많은 장기유지(long-lasting)되는 네트워크 연결을 핸들링하는데 좋은 Twisted를 사용하였기 때문에잘 작동되었다. 많은 long-lasting 연결을 핸들링하는데 아파치가 좋지 않게 됨에 따라 Twisted server의 앞단에 아파치 reverse proxy를 넣는 것은 performance와 scalibility를 손상시키는 주된 요인이될 것이다. 그리고 LivePage가 XHR에 제약을 받게됨에 따라 나는 궁극적으로 non-XHR를 사용할수가 없었다.

JotSpot과 함께 우리의 접근방식은 Twisted server가 모든 페이지의 요청과 XHR 호출을 핸들링하게 하였다. 그것은 JotSpot이 웹사이트 전용으로 standalone일때까지는 좋았다. 그러나 우리의 고객들이 요구하는 것은 보통 xxx.jot.com 사이트에서 Live-style의 실시간 업데이트를 할 수 있는 능력이었다. 그리고 우리는 우리의 도메인에 있는 모든 사이트의 앞단에 Twisted server를 넣는것을 원치 않았다. 따라서 나는 우리의 도에인의 모든 페이지에서도 XHR을 통해 live.jot.com과 통신할수 있게 할 수 있도록 하는 방법을 찾기 시작하였다. 결론적으로, 그것은 가능했다. 하지만 어떤 hoops를 뛰어넘어야만 한다. 여기 있는 예제들에 대해서 두가지를 알아둬라:

  • 나는 실제로 두개의 다른 server를 사용하지 않았다. 나의 예제에서, http://fetting.net/에 있는 페이지는 http://www.fetting.net/.에 XHR호출생성을 시도할 것이다.사실은 나의 아파치가 동일한 가상호스트를 만드는 것이 브라우저에게는 다르지 않게 보인다. 그것들이 같은 hostname을 가지고 있지 않다고 하더라도,그리고 두개의 다른 내용을 가지고 있는 다른 사이트라고 하더라도 다르지않게 취급되어진다. 만약 내가 ajax.fetting.net서버에 그것의 IP주소와 함께 XHR호출을 한다면 결과는 다르지 않다.
  • 나는 getUrl 한수를 제공해주는 간단한 XHR wrapper library를 사용하였다. getUrl은 URL과 callback 함수를 취하고, URL로 XHR연결을 열어준다, 그리고, 결과와 함께 함수를 호출한다. 만약 이것이 흥미롭다면 여기에서 full code를 볼 수 있다.
  • 내가 XHR호출을 만드는 서비스는 간단한 PHP페이지(ajaxdata.php)로 server에서의 편재 UNIX 시간을 출력한다 : 실제로는 그리 유용하지 않지만 테스트를 목적으로 하기에는 충분히 좋다.

첫번째 시도 : 고지식한 접근방식

여기 내가 시도한 첫번째 방식이 있다 :

다른 subdomain의 페이지의 full URL과 함께하는 XHR. 나는 이것은 동작하지 않을 것이라 확신했지만, 나는 이것을 검증해보고 싶었다 :

  1. <html>
    1. <head>
      1. <script type=”text/javascript” src=”xmlhttp.js”></script>
      2. <script type=”text/javascript”>
        1. var AJAX_URL=”http://www.fettig.net/playground/ajax-subdomain/ajaxdata.php”;
        2. function getTime(){
          1. getUrl(AJAX_URL, gotTime);
        3. }
        4. function gotTime(status, headers, result) {
          1. document.getElementById(’time’).innerHTML = result;
          2. setTimeout(getTime, 1000)
          3. }
        5. window.onload = getTime;
      3. </script>
    2. </head>
    3. <body>
    4. <div id=”time”>
    5. </div>
    6. </body>
  2. </html>
이 페이지는 fetting.net으로부터 전달되어졌고, www.fetting.net으로 XHR 호출을 생성하려하고 있다. 실제로는, 이러한 것들이 같은 server겠지만, browser는 그것을 알지 못한다. 놀랄것도 없이, 이것은 어떤 브라우저에서도 동작하지 않는다. 당신은 다음과 같은 security error를 받을 것이다(firefox로 부터) :
  1. uncaught exception : Permission denied to call method XMLHttpRequest.open
당신은 여기서 그것을 해볼 수 있다.

두번째 시도 : iframe과 document.domain 사용하기

나의 최근 JotSpot 사무실로의 방문에서 Alex는  iframe과 document.domain 프로퍼티를 가르쳐주었다. iframe은 다른 페이지로부터 현재의 페이지에 데이터가 로드되는 것은 XHR과 유사하다. 그러나 iframe은 그것들이 포함하고 있는 페이지들과 동일한 웹서버로부터 당겨오는 페이지에 한계가 없다 - 그들은 그 어떤 URL도 로드할 수 있다. cross-site 보안문제를 예방하기 위해서 브라우저는 javascript object model에 same origin policy를 강요한다:한 frame에서 동작하는 script는 각각의 페이지가 동일한 서버에서 온 것이라 할 지라도, 다른 어떤 iframe 안에 있는 객체에도 접근을 할 수 없다. 그러나, 이러한 규칙에도 예외가 있다. 만약 각각의 페이지가 동일한 parent domain으로 부터 왔고, 각각의 document.domain프로퍼티에 동일한 parent domain을 가리키도록 설정하면, 각각의  iframe에서 동작하나는 script는 각각 서로간에 통신을 허용할 것이다.

예를 들어, http://www.example.com/http://ajax.example.com/을 iframe에 로드한다고 하자. 각각의 페이지가 example.com 도메인에 있는 한, 만약 각각의 document.domain이 "example.com"으로 설정되어 있다면 그것들은 서로간의 데이터에 접근을할 수 있게된다.

그럼, 당신은 iframe과 document.domain을 XHR 연결에 사용할 수 있는 것인가? 두가지의 제약사항과 함께 가능하다.

  1. iframe은 반드시 당신이 XHR호출을 하는 서버로부터 와야 한다.
  2. 반드시 document.domain을 설정하기 전에 XHR 연결(open)을 해야만 한다.

여기 내가 사용한 코드가 있다. 첫번째로, test2.html :

  1. <html>
    1. <head>
      1. <script type=”text/javascript”>
        1. document.domain=”fettig.net”;
        2. function gotTime(result) {
          1. document.getElementById(’time’).innerHTML = “Server timestamp: ” + result;
        3. }
      2. </script>
    2. </head>
    3. <body>  
      1. Single XmlHttpRequest. Works in all modern browsers.
      2. <div id=”time”></div>
      3. <iframe src=”http://www.fettig.net/playground/ajax-subdomain/test2-iframe.html”>    </iframe>
    4. </body>
  2. </html>
이 페이지의 script는  document.domain을 설정하고, XHR 호출의 결과를 핸들링하는 gotTime 함수를 정의한다. 모든 XHR 덩어리들은 iframe에서 일어난다. 여기에 test2-iframe.html코드가 있다 :
  1. <html>
    1. <head>
      1. <script type=”text/javascript” src=”xmlhttp.js”></script>
      2. <script type=”text/javascript”>  
        1. var AJAX_URL=”http://www.fettig.net/playground/ajax-subdomain/ajaxdata.php”;    function gotResult(status, headers, result) {
          1. document.domain = “fettig.net”; // set d.d before talking to parent frame      window.parent.gotTime(result);
        2. }
        3. getUrl(AJAX_URL, gotResult);
      3. </script>
    2. </head>
  2. </html>

test2-iframe.html은 www.fetting.net에 XHR호출을 만든다. 그것은 www.fetting.net으로 부터 왔기때문에 가능한 것이다. 따라서 그것은 단지 그것의 원천 서버에 요청을 하것 뿐이다. 그것이 한번 응답을 받으면, 그것은 parent frame의 document.domain과 매칭시키기 위하여  document.domain을 fetting.net으로 설정한다.이제 그것은 javascript를 사용하여 parent frame에 요청을할 수 있다. 따라서 그것은 window.parent.gotTime을 하는것이 가능하다.

이것을 하기 위한 중점은 올바른 요청에 있다. 당신이 한번 document.domain을 설정하면 당신은 XHR 호출을 만들 수 잇는 능력을 잃게 된다. 따라서 당신은 document.domain을 설정하고 parent frame과 통신을 가능케 하기 전에 당신의 XHR 작업에 신경을 써야할 것이다.

Konq이러한 규칙을 따르면 잘 작동할 것이다. 이 기술들은 현대의 모든 브라우저에 잘 작동되어진다(나는 IE6, Firefox1.0.7, Safari 1.3, Opera8.5, 그리고ueror 3.4에서 테스트를 해보았다)
당신은 여기에서 그것들은 테스트해볼수 있다.

세번째 시도 :  XmlHttpRequest 반복하기

나는 우리의 도메인에 있는 다른 서버로 한개의 XHR을 생성하는 방법을 해결하여 기뻤다.  그러나 현시점에서 이 기술은 거의 심각한 한계를 가지고 있다.:당신은 XHR호출을 당신이 document.domain을 설정한 시점에서만 할 수 있다. 당신이 한번 그렇게 하면, 당신은 parent frame과 통신할 수 있는 능력을 얻게 되지만, 앞으로 XHR 호출을 할수있는 능력은 잃게 된다. 계속적으로 서버에 XHR 호출을 생성하고 결과를 핸들링해야하는 능력이 필요한 LivePage에게는 이것은 좋지 못한 방법이었다. 나는 iframe이 server(XHR를 사용하여)와 parent frame(document.domain을 설정해야지만 할 수 있는)과의 통신 모두를 할 수 있는 방법이 필요했다.

이로서 질문한가지를 떠오르게 하였다 : document.domain 프로퍼티를 한번만 설정할수 있는가? 혹은 fly에서 그것을 switch할 수 있는가? 만약 그 변경을 앞으로 혹은 뒤로 되돌릴수 있다면, 그것을 앞으로 뒤로 바꾸는 것은 가능할 것이다. 여기에 iframe의 수정된 버전인 test3-iframe.html이 있다.

  1. <html>
    1. <head>
      1. <script type=”text/javascript” src=”xmlhttp.js”></script>
      2. <script type=”text/javascript”>  
        1. var AJAX_URL=”http://www.fettig.net/playground/ajax-subdomain/ajaxdata.php”;
        2. function gotResult(status, headers, result) {
          1. var oldDomain = document.domain;
          2. document.domain = “fettig.net”;
          3. window.parent.gotTime(result);
          4. document.domain = oldDomain;
          5. setTimeout(getTime, 1000);
        3. }
        4. function getTime(){    
          1. getUrl(AJAX_URL, gotResult);
        5. }
        6. getTime();
        7. </script>
      3. </head>
    2. </html>
결과는 test2-iframe.html에서와 비슷하게, test3-iframe.html에 있는 gotResult 함수는 document.domain을 fetting.net(parent frame에 접근을 가능케 하기 위해)로 설정하고 window.parent.gotTime을 호출한다. 그러나 첫번째로 해당 페이지가 전송되어진 호스트를 디폴트로 하는 현재의 document.domain값을 저장해놓는다. 그것은 parent와의 작접을 끝낸 후, 그것은 document.domain을 원래의 값(XHR 을 생성할 수 있는 처음에 저장한 domain주소)으로 바꾸어 설정한다.  그런다음 그것은 다른 XHR 호출을 설정하기 위하여 setTimeout을 사용한다. 결과는 main page에서 timestamp가 계속해서 갱신되어져야만 한다.
당신은이 동작을 여기서볼수 있다.
이 페이지는 iframe이 각 시간마다 parent page에 있는 함수를 호출하고 XHR을 반복적으로 생성해내고 서버로부터 결과를 얻어낸다 . 불행하게도 이 기술은 IE,Safari,Knqueror에서는 잘 작동되지만 Mozilla와 Opera에서는 작동하지 않는다. 첫번째 XHR은 동작을 하지만, document.domain을 원래의 값으로 바꾸려고 할때 오류가 발생할 것이다. Firefox에서는 다음과 같은 error message를 발생시킨다.
  1. Error: [Exception... "Illegal document.domain value"   code: “1009″  nsresult: “0×805303f1 (NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN)”   location: “http://www.fettig.net/playground/ajax-subdomain/test3-iframe.html  Line: 13″]
Mozilla와 Opera는 document.domain의 값에 대해서 더욱 엄격하다 - 그것은 오직 현재의 값이나 더 상위 레벨의 도메인으로만 설정이 가능하다.예를 들어서 만약 호스트가 aaa.bbb.example.com이라면, 나는 document.domain을 bbb.example.com으로 바꿀수 있다. 이러한 점에서 나는 그것을 다시 example.com으로 바꿀수 있었지만, 다시 aaa.bbb.example.com으로 되돌릴수는 없었다. 한번 당신이 상위레벨의 도메인으로 옮겼다면 다시는 하위레벨로 수정할수가 없어서 곤경에 빠질 것이다.

네번째 시도 : Mozilla에서 동작하게 하기

나는 Opera없이 살 수 있지만 Mozilla없이는 살 수 없다. 따라서 나는 그 문제를 해결할 수 있는 방법을 찾아내야 했다. 잠시동안 그것에 대해서 생각해본뒤 나는 의문이 생기기 시작하였다 : frame들간에 통신에 있어서 보안상의 제한이 단지 어떻게 엄격하게 규정되어지는가? 우리는 브라우저들이 해당 frame의 document.domain이 같은 값을 가지고 있지 않은 이상은 다른 프레임으로의 접근을 하지 못하도록 한다는 것을 알고 있다. 따라서 child frame들의 document.domain을 설정이 parent의 그것과 같지 않다면 child에서 window.parent.foo에 접근하는 것은 불가능 하다. 그러나 만약 당신이 parent frame에 있는 함수를 지시할수 있도록 childframe에 있는 attribute를 설정할 수 있다면, 그리고 document.domain을 바꿀 수 있다면 어떤가? child frame은 여전히 함수를 호출할수 있을까? 대답은 "그렇다"이다. 그리고 그것은 내가 Mozilla에서 작업하는데 있어서 필요로 하는 것을 충족시켜주었따. 방법은 두개의 frame을 사용하는 것:

  1. parent window  bridge iframe  child iframe
bridge iframe과 child iframe은 모두 당신이 XHR 호출을 만들고자 하는 서버로부터 존성되어졌다. parent apge 코드는 위에서의 예제와 동일하다 :그것은 XHR의 결과를 핸들링하는 함수를 정의하고, iframe을 로딩한다. 여기서는 bridge code를 보자 :
  1. <html>
    1. <head>
      1. <script type=”text/javascript” src=”xmlhttp.js”></script>
      2. <script type=”text/javascript”>  
        1. function gotTime(result) {    
          1. window.parent.gotTime(result); // pass result up to the parent  
        2. }  
        3. window.onload = function(){
          1. var subframe = document.createElement(’iframe’);      document.body.appendChild(subframe);
          2. subframe.src = “test4-iframe.html”;
          3. subframe.contentWindow.bridgeGotTime = gotTime;
          4. document.domain = “fettig.net”;
        4. }
      3. </script>
    2. </head>
    3. <body>
    4. </body>
  2. </html>

이 frame이 로드될때, 그것은 다른 frame 그 안에 로드한다. child frame이 bridge frame과 동일한 서버로부터 로딩되어지는 한, bridge frame은 script를 통해서 child frame의 객체에 접근할 수 있다.bridge frame은 그것만의 gotTime에 subframe.contentWindow.bridgeGotTime를 설정한다. 다음으로 bridge frame은 그것의 document.domain을 그것의 parent widnow의 그것과 매칭시켜 변경한다.이 시점에서 bridge frame은 그들의 document.domain 프로퍼티가 매칭되지 않을때까지 child frame에 직접적으로 통신할수 있는 능력을 잃게 된다. 그러나 child frame은 처음에 설정해놓았던 bridgeGotTime 함수를 통해서 bridge frame과 통신을할수 있는 능력을 유지할수 있게된다. 그리고 bridge frame의 document.domain이 parent의 document.domain과 매칭되는한, bridge와 parent는 자유롭게 통신할수 있다. 나의 제한적인 테스팅에서는,이 기술은 오직 Mozilla-based 브라우저에서만 작동하는것처럼 보였다. (나는 Opera에 대한 방법을 찾지 못했지만, 여기에 시간을 많이 소비할 생각은 없다).

나의 마지막 예제에서는 document.domain을 switching하고, 만약 당신이 document.domain을 재설정하려고 할때 브라우저가 에러를 발생시킨다면 bridge-iframe에 의지할 수 있는 hybrid적인 접근방식을 사용하였다. 여기 main page code가 있다 :

  1. <html>
    1. <head>
      1. <script type=”text/javascript”>
        1. document.domain=”fettig.net”;
        2. function gotTime(result) {
          1. document.getElementById(’time’).innerHTML = “Server timestamp: ” + result;
        3. }
      2. </script>
    2. </head>
    3. <body>
      1. <div id=”time”></div>
      2. <iframe src=”http://www.fettig.net/playground/ajax-subdomain/test4-iframe.html”></iframe>
    4. </body>
  2. </html>
여기까지는 iframe이  test4-iframe.html으로부터 로드되어져 온다는 것을 제외하고는 모든것이 동일하다. 여기 그 페이지의 코드가 있다 :
  1. <html>
    1. <head>
      1. <script type=”text/javascript” src=”xmlhttp.js”></script>
      2. <script type=”text/javascript”>  
        1. var AJAX_URL=”http://www.fettig.net/playground/ajax-subdomain/ajaxdata.php”;    function getTime(){
          1. getUrl(AJAX_URL, gotTime);
        2. }
        3. function gotTime(status, headers, result) {
          1. var oldDomain = document.domain;
            1. if (window.bridgeGotTime) {
              1. window.bridgeGotTime(result);    
            2. } else {
              1. document.domain = “fettig.net”;      
              2. window.parent.gotTime(result);    
            3. }
            4. try {
              1. document.domain = oldDomain;
              2. setTimeout(getTime, 1000);    
            5. } catch(e) {
              1. // denied access to switching the domain, use bridge instead        document.location.replace(”test4-bridge.html”);    
            6. }  
          2. }  
          3. getTime();
          4. </script>
        4. </head>
      3. </html>

이 코드는 XHR서버와 parent frame 각각에 대하여 통신할 필요가 있을때마다 document.domain을 전 후로 변환하는 것을 시도한다. 그러나, 만약에 이것이 실패한다면  그것은 대신하여 bridge iframe을 로드할 것이다. 두개의 다른 페이지가 동일한 일을 하게 하기 위하여,이 페이지는 bridge frame의 child로서도 수행되어진다. 만약 그것이 widnow.bridgeGotTime 어트리뷰트를 보게 되면 그것은 bridge iframe의 아래에서 수행되어진다는 것을알수 있을 것이고, 따라서 그것은 직접적으로 widnow.parent를 요청하는 대신에 window.bridgeGotTime를 요청할 것이다.

당신은 이 액션을 test4.html에서 볼 수 있다. 그것은 Opera를 제외한 최근 모든 브라우저에서 작동한다.

Update : test5.html를 사용하라(갱신되었음). 자세한 내용은 여기 참고

결론 :  당신의 도메인에서 다른 서버에 XHR호출을 만드는 것은 가능하다. 만약 당신이 약간의 설정상의 오버로드를 감안할 의지가 있다면 당신은 반복적으로 호출할 수도 있다. 이것은 여러가지의 이점을 가지고 있다 :
  1. 만약 페이지의 주요 컨텐츠가 아파치나 다른 어떤 웹서버로부터 불러져온다면 그동안 LivePage 요청은을 핸들링하는 전용 Twisted server 를 가질 수 있다.
  2. XHR을 포함하는 웹서비스를 핸들링할수 있는 전용 서버를 가질 수 있다.
  3. two-max-connection이라는 브라우저의 한계로부터 DNS에서 자유롭게 XHR를 사용할 수 있다. 브라우저는 당신이  한번에 두개가 넘은 연결을 할수 없게할 것이다-만약 당신이 JotSpot Live와같은 어플리케이션을 사용하고 한번에 한개가 넘는 탭으로 이동하려고 한다면 뒤죽박죽이 되어질 수 있다. 그러나 만약 XHR이 같은 서버에서 호출되지 않아도 된다면, 당신은 wildcard DNS를 사용할 수 있고,
2007/10/09 13:51 2007/10/09 13:51
이 글에는 트랙백을 보낼 수 없습니다

Ajax에서 서버와의 통신을 위한 핵심 요소인 XMLHttp는

IE7과 모질라 계열 브라우저에서는 native XMLHttpRequest를 사용.
그리고 IE6 이하 버전에서는 Microsoft.XMLHttp를 ActiveXObject로 object 생성.

[ IE에서 생성할 수 있는 XMLHttp object ]
  - Microsoft.XMLHttp
  - MSXML2.XMLHttp
  - MSXML2.XMLHttp.3.0
  - MSXML2.XMLHttp.4.0
  - MSXML2.XMLHttp.5.0


[ Cross-Browser 를 위한 XMLHttp object 메소드 생성 예 ]

function CreateXMLHttp()
{
  if (window.XMLHttpRequest)
  {
    return new XMLHttpRequest();
  }
  else if (window.ActiveXObject)
  {
    var aVersions = [ "MSXML2.XMLHttp.5.0"
      ,"MSXML2.XMLHttp.4.0"
      ,"MSXML2.XMLHttp.3.0"
      ,"MSXML2.XMLHttp"
      ,"Microsoft.XMLHttp"
      ];

    for (var i = 0; i < aVersions.length; i++)
    {
      try
      {
        var oXmlHttp = new ActiveXObject(aVersions[i]);
        return oXmlHttp;
      }
      catch (oError)
      {    
      }
    }
  }
}


[XMLHttp의 메소드 , 프로퍼티 및 이벤트]
1. 메소드
- abort( ) : 요청을 취소
- getAllResponseHeaders( ) : 모든 응답 헤더를 수신
- getResponseHeader(header) : 특정 응답 헤더 수신
- open(RequestType, url, async) : 통신 연결(nativ XMLHttpRequest는 Cross-domain을 제한함.)
   - RequestType : Get or Post

   - url : 서버 주소
   - async : true(비동기 방식 통신), false(동기 방식)
  
- send(content) : 서버로 요청을 보냄. content는 null 을 포함함.
- setHeader(header, value) : 헤더의 키와 값의 쌍을 설정

2. 프로퍼티 / 이벤트 핸들러
- onreadystatechange : readyState가 변경 시 실행될 함수 등록
- readyState : 요청 및 처리 상태
   - 0 (Uninitialized) : 아직 open() 메소드를 호출 하지 않은 상태
   - 1 (Loading) : open() 메소드를 호출한 상태(아직 send는 하지 않은 시점)
   - 2 (Loaded) : 요청을 서보로 보낸 상태( send() )
   - 3 (Interactive) : 일부만 응답 받은 상태
   - 4 (Complete): 모든 데이터를 받고 연결이 끊어진 상태

- responseText : 서버로 부터 받은 결과값의 스트링 반환
- responseXML : 서버로 부터 받은 결과값의 XML 형식
- status  : 서버로 부터 응답 받은 상태 코드 (200 (OK) or 404 (Not Found) 등)
- statusText : status 코드에 대한 의미 명기


[ 서버 전송 예 ]
function sendRequest()
{
    var content = getRequestBody();

    var oXmlHttp = createXMLHttp();
    oXmlHttp.open("post", "http://www.text.com/testForm.aspx", true);
    oXmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

    //서버로 호출이 성공 하였을 경우 처리할 CallBack 함수 등록
    oXmlHttp.onreadystatechange = function ()
    {
        if (oXmlHttp.readyState == 4)
        {
            if (oXmlHttp.status == 200)
            {
                saveResult(oXmlHttp.responseText);
            }
            else
            {
                saveResult("An error occurred: "+ oXmlHttp.statusText);
            }
        }
    };
    
    oXmlHttp.send(content);
}


----------------------- 에이작스 한글깨짐 -----------------------------

JavaScript --> PHP

encodeURIComponent( string ) --> iconv( "UTF-8", "CP949", rawurldecode($string ) )


PHP --> JavaScript

rawurlencode( iconv( "CP949", "UTF-8", $string ) ) --> decodeURIComponent( string )


JSP/Servlet 에서 Ajax와 한글 인코딩 문제


Ajax는 기본적으로 UTF-8 만으로 통신을 한다고 보면된다. 그 이외의 Encoding을 지원하는 인코딩 함수가 없기 때문에 EUC-KR로 데이터를 전송하려는 꿈은 접어야만 한다.
헌데, 아직 우리나라는 EUC-KR 인코딩으로 된 웹 어플리케이션이 압도적으로 많은 상황이다(어서 빨리 UTF-8로 옮겨가길 바라마지 않는다).
거기다가 보통 JSP/Servlet 웹 어플리케이션은 Servlet 스펙 2.3이후부터 문자 인코딩 서블릿 필터를 사용해 모든 요청에 대해 일관된 문자 인코딩을 사용하는 것이 보편적인 방법으로 자리잡았다.

서블릿 필터는 일관성있게 모든 요청을 EUC-KR로 받아들이게 했는데, 몇몇 Ajax관련 요청만 UTF-8로 받아들여야만 하는 것이다.
필터를 적용할 URL-Pattern을 따로 줘보려 했으나, 너무 복잡해졌다.
그래서 HTTP 요청의 헤더를 이용해서 해결 했다.

아.. 한가지 더. 현재 한글 문제는 "XMLHttpRequest 요청 -> JSP/Servlet" 이 상황에서만 발생하는 것이다.
"JSP/Servlet -> XMLHttpRequest"의 상황(서버에서 클라이언트로 값을 리턴)에서는 이 문제가 발생하지 않는다.
서버가 리턴하는 문자열은 간단하게 다음처럼 하면 WAS가 자동으로 UTF-8로 값을 변경해서 전달하기 때문이다.

<%@ page contentType="text/plain; charset=utf-8" pageEncoding="EUC-KR"%>


contentType에서 text/plain은 텍스트나 JSON으로 값을 리턴할 때이다. XML로 리턴할 때는 text/xml.

아래는 Ajax 요청을 처리하기 위해서 만들어본 간단한 Encoding Filter 이다.

package ajax.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 어플리케이션 전체에 적용되는 필터이다.
 *
 * <ul>
 * <li>encoding 파라미터 : encoding 파라미터를 설정하면 request 객체에
 * setCharacterEncoding(encoding)을 실행한다.</li>
 * <li>ajaxFlag 파라미터 : Ajax요청임을 나타내는 HTTP 파라미터 이름이다. ajaxFilter로 지정한 HTTP 파라미터의
 * 값이 true 로 설정되면 인코딩을 무조건 UTF-8로 설정한다.</li>
 * </ul>
 *
 * @author 손권남(kwon37xi@yahoo.co.kr)
 *
 */
public class EncodingFilter implements Filter {

    private Log log = LogFactory.getLog(this.getClass());

    /** HTTP 요청 문자 인코딩 */
    private String encoding = null;

    /** Ajax 요청임을 나타내는 플래그 파라미터 이름 */
    private String ajaxFlag = null;

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        if (ajaxFlag != null
                && "true".equals(((HttpServletRequest) request)
                        .getHeader(ajaxFlag))) {
            // Ajax 처리 요청일 경우 무조건 UTF-8 지정.
            request.setCharacterEncoding("UTF-8");
            if (log.isDebugEnabled()) {
                log.debug("요청 헤더에 " + ajaxFlag + "가 "
                        + ((HttpServletRequest) request).getHeader(ajaxFlag)
                        + "로 설정되어 있어 문자 인코딩에  UTF-8을 사용합니다.");
            }
        } else if (encoding != null) {
            // Ajax 플래그가 true가 아니면, 기본적인 인코딩을 적용한다.
            request.setCharacterEncoding(encoding);
            if (log.isDebugEnabled()) {
                log.debug("문자 인코딩에 " + encoding + "을 사용합니다.");
            }
        }

        chain.doFilter(request, response);
    }

    public void init(FilterConfig config) throws ServletException {
        encoding = config.getInitParameter("encoding");

        ajaxFlag = config.getInitParameter("ajaxFlag");

        if (log.isDebugEnabled()) {
            log.info("encoding : " + encoding + ", ajaxFlag : " + ajaxFlag);
        }
    }

    public void destroy() {
    }
}

이 필터를 적용하고서, web.xml에 다음 내용을 추가하면 필터가 작동한다.
<filter>
    <description>이중 인코딩 필터</description>
    <filter-name>EncodingFilter</filter-name>
    <filter-class>ajax.filter.EncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>euc-kr</param-value>
    </init-param>
    <init-param>
        <param-name>ajaxFlag</param-name>
        <param-value>Ajax</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>EncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

여 기 내용을 보면, 기본적인 인코딩은 EUC-KR이고, 요청 헤더에 "Ajax" 헤더의 값이 "true"일 경우에는 강제로 UTF-8을 지정하라고 한 것이다. "ajaxFlag"의 값을 변경하면 헤더의 키을 "Ajax"가 아닌 다른 값으로도 지정할 수 있다. 하지만 아무튼 해당 헤더의 값을 "true"로 지정하면 Ajax로 인식하게 되는 것이다.

이를 위해서는 XMLHttpRequest에도 한가지 처리를 더 보태야 한다.
2007/07/31 11:50 2007/07/31 11:50
이 글에는 트랙백을 보낼 수 없습니다
웅쓰:웅자의 상상플러스
웅자의 상상플러스
전체 (379)
게임 (5)
영화 (2)
기타 (23)
맛집 (5)
영어 (2)
대수학 (3)
형태소 (5)
Hacking (9)
Linux (112)
HTML (48)
Application_developing (48)
Web_developing (102)
Window (11)
«   2024/05   »
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
  1. 2016/01 (1)
  2. 2015/12 (3)
  3. 2015/10 (3)
  4. 2015/03 (2)
  5. 2015/01 (4)