2009-11-26

AJAX를 사용할 수 없을 때

도메인이 다르면 AJAX를 사용할 수 없다. 자바 스크립트로 이를 흉내내는 방법이 있다.

var HTTP = {};

HTTP.getTextWithScript = function(url, callback) {
    var script = document.createElement("script");
    document.body.appendChild(script);
    var funcname = "func" + HTTP.getTextWithScript.counter++;
    HTTP.getTextWithScript[funcname] = function(text) {
                                           callback(text);
                                           document.body.removeChild(script);
                                           delete HTTP.getTextWithScript[funcname];
                                       }
    var emptyImage = new Image();
    emptyImage.onerror =
        function() {
            Progress.hide();
            callback("<div>Error Happened</div>");
        };
    emptyImage.onload =
        function() {
            script.src = HTTP.url + url + "&func=" + encodeURIComponent("HTTP.getTextWithScript." + funcname);
        };
    emptyImage.src = HTTP.url + "/empty.gif";
}

HTTP.getTextWithScript.counter = 0;

해당 서버에 empty.gif 이미지가 존재해야 한다. 서버가 응답하면 문제가 없지만 그렇지 않으면 행이 걸릴 수 있다. 이를 방지하기 위해서 이미지 파일를 이용한다.



사용 방법은 다음과 같다.

HTTP.url = url;
Progress.show("result");
HTTP.getTextWithScript("/some_request",
                       function(text) {
                           $("result").innerHTML = text;
                           Progress.hide();
                           DocResize.adjustHeight();
                       }
                       );



자바(서버 사이드)에서는 다음과 같이 처리한다.

JavascriptCallResponse javascriptResponse = new JavascriptCallResponse(response);
include(request, javascriptResponse, "actual_page.jsp");

response.setContentType("text/javascript; charset=UTF-8");
String func = request.getParameter("func");
PrintWriter writer = response.getWriter();
String text = StringUtils.strip(javascriptResponse.getContent().toString()).replaceAll("(?m)\\s+", " ");
writer.write(func + "('" + text + "');");

실제 화면 로직 처리는 actual_page.jsp에 있다.


JavascriptCallResponse 클래스는 다음과 같다.

package com.dimdol.example;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class JavascriptCallResponse extends HttpServletResponseWrapper {

    private PrintWriter writer;

    private StringWriter stringWriter;

    public ReportServletResponse(HttpServletResponse response) {
        super(response);
    }

    public String getContentType() {
        return "text/html; charset=UTF-8";
    }

    public PrintWriter getWriter() throws IOException {
        if (writer == null) {
            stringWriter = new StringWriter();
            writer = new PrintWriter(stringWriter);
        }
        return writer;
    }

    public StringBuffer getContent() {
        return stringWriter == null ? new StringBuffer() : stringWriter.getBuffer();
    }

}



* 보안 문제일까? 일부 웹 브라우저에서는 동작하지 않는다. 그래서 이 방법보다는 서버에서 프락시 방식으로 처리하는 걸 선호한다.


* JavaScript: The Definitive Guide에 있는 내용을 참조

1 comment:

Simulz said...

trackback from: (jQuery) JSONP로 크로스 도메인 원격 데이터 가져오기
준비물: (jQuery) 연결하기 브라우저 기본 보안 설정으로는 현재 페이지의 호스트가 아닌 다른 서버에 HTTP 요청을 할 수 없다. 하지만 JSONP를 사용하면 보안 설정을 바꾸지 않고도 원격 데이터를 가져올 수 있다. 이 블로그에서는 게시물 아래 인기순 Top 글 목록에 적용되어있다. 데이터를 보내줄 원격 도메인 쪽에 JSON 형식으로 출력하도록 PHP 스크립트 코드를 작성한다. <?php $json['key'] = '여러 형식의 데이터'; e..