지난 글에 이어 생각해 볼만한 문제 회피 방법을 소개할까합니다. domain이 다른 상황에서 데이터를 요구하거나 전송하고자할 때 사용하는 방법으로 script tag 삽입(dynamic script tag)이라는 기법이 사용됩니다. (참고 1: 구글 책 검색) (참고2)

www.example.com: main.html
<script>
function draw( result )
{
    if( result ) { alert("성공"); } else { alert("실패"); }
}

function addComment( id, comment )
{
    var scr = document.createElement( "SCRIPT" );
    scr.src = "http://external.example.net/api/get_tags?article_id="+
id+"&comment="+encodeURIcomponent(comment)+"&callback=draw";
    document.body.appendChild( scr );
}
</script>
위 스크립트는 도메인이 www.example.com에 있으면서, external.example.net이라는 외부 도메인의 글에 댓글을 달 수 있는 방법에 대한 하나의 예시입니다. 전형적이죠.

위 방법의 단점이 있으니 그것은, 위 방법은 GET 방식을 통해 이루어지는 URL 길이 제한에 걸린다는 것입니다.

검색 결과를 참고해봐서 인용하자면,
IE: 2083, FF: 65,536, Safari: 8,000, Opera: 190,000
Apache: ~4,000 IIS: 16,384
http://www.boutell.com/newfaq/misc/urllength.html
정도입니다.
아쉽게도 IE의 경우 2083자 정도이고, 이것은 UTF8의 경우 URL에서 한글 인코딩은 한 글자당 9byte를 소비하므로, 호스트명이나 변수명등을 제외하면, 200자정도로 제한 되는 것을 알 수 있습니다.

따라서, POST를 쓸 수 밖에 없습니다만, 이 경우 script 태그를 통한 방법으로는 GET만 가능하므로 어렵습니다. 숨겨진 IFRAME을 만들고, 이 녀석 안에서 FORM을 만들어 전송하는 방법으로 해야겠습니다.

다음과 같은 방법을 소개합니다.

example.com: main.html
<script>
var request = {};
var requestCount = 0;
function addComment( id, comment )
{
    request[requestCount] = {id:id, comment:comment};
    var irf = document.createElement( "IFRAME" );
    ifr.src = "post.html#"+ requestCount;
    requestCount++;
    document.body.appendChild( ifr );
}
</script>
example.com: post.html
<html>
<head><meta http-equiv="Content-Type"
content="text/html; charset=utf-8" /></head>
<body>
<script>
var request = window.parent.request[document.location.hash.substr(1)];
var form = document.createElement( 'FORM' );
var key = document.createElement( 'INPUT' );
var value = document.createElement( 'INPUT' );

form.action =
"http://external.example.net/api/addComment?callback=dummy";

form.method = "post";
key.name = "article_id";
key.value = request.id;
value.name = "comment";
value.value = request.comment;

document.body.appendChild( form );
form.appendChild( person_id );
form.appendChild( key );
form.appendChild( value );
form.submit();
</script>
</body>
</html>

/* Dynamic script tag technique has limitation of URL max length */
원리는 간단합니다. 숨겨 있는 IFRAME에서 자기의 주소 뒤에 오는 fragment (#) 부분을 해석하여, 부모 프레임에 숨겨 있는 개체에 접근합니다. 주소에 넣기 싫다면, 숨겨 있는 frame을 만들때 name에 넣어주고, window.name으로 접근해도 됩니다.

간단하죠? 단,iframe을 사용할 경우, iframe이므로 /api/addComment의 결과는 text/html과 같이 브라우져 안에서 해결할 수 있는 MIME 형식이어야합니다. 또한 callback이 동작하지 않습니다. FORM이 전송되고 나면, iframe은 더이상 www.example.com이 아닌 external.example.net 소속이 되므로, 부모에 접근할 수 없게 됩니다. 꼭, callback을 호출하고 싶을 때는 api의 결과창이 다시 redirect되어 상위에 접근할 수 있도록 바뀌어야합니다. 이것은 숙제로 남겨 둡....니다.
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

+ Recent posts