uncaught exception : Location.toString 문제점과 해결책
언젠가 한번 이 에러를 꼭 잡겠다고 마음먹었는데, 오늘 갑자기 필 받아서 3시간 넘게 삽질해서 드디어 밝혀냈습니다. 원인을 알고나니 허탈하군요. orz
__________________________
Firefox의 확장기능인 Firebug를 켜둔 채로 웹 사이트를 돌아다니다보면 어떤 사이트에서 에러가 나는지, 어떤 에러가 어느 위치의 코드에서 발생했는지 친절하게 알려준다. 하지만 가끔은 원인을 알 수 없는 메시지를 보여주기도 하는데, 그 중 가장 자주 보이는 메세지가 uncaught exception : Location.toString 인 것 같다.
간단하게 예를 들어보자. 네이버 메인 페이지에 들어가면 가끔 Firebug에서 에러를 알려주는 영역에 다음과 같이 경고 아이콘이 나타나는 것을 알 수 있다.
그림 1. 네이버 메인의 오류
이 아이콘을 클릭하면 에러 메시지가 나타난다.

그림 2. Firebug 콘솔에 나타난 오류 메시지
참고로, uncaught exception: Location.toString 1 8 p 라는 메시지는 동일근원 정책(Same-Origin Policy)에 위배되는 동작을 시도할 때 나타난다. XMLHTTPRequest 로 다른 도메인에 접근하려한다거나, 도메인이 서로 다른 프레임끼리 스크립트로 접근하는 경우가 그러하다. 따라서, 오류가 발생하는 부분을 찾아 관련 행위를 하는 코드를 찾으면 해결할 수 있다. 보통 이런 경우에는 XHR이 아닌 JSONP등의 크로스 도메인이 가능한 다른 방식을 이용해서 Ajax 호출을 하거나, 프레임끼리의 도메인을 document.domain = “domain.com”; 코드로 맞추어 주면 해결가능하다(단, document.domain은 같은 도메인의 서브 도메인끼리만 가능).
그래서, 처음엔 이걸로 해결할 수 있겠다라고 생각했었다. 하지만, 안타깝지만 이 문제는 Firebug도 해결할 수 없다. 문제를 해결하기 위해 Fiddler를 이용해 onLoadComplete()가 정의되어 있는 www.js를 로컬 파일로 대체하고 searchrank() 함수를 주석처리했다.

그림 3. onLoadComplete() 함수
그래서 잘 됐냐고? 앞서 말했듯 “해결할 수 없었다”. 심지어 onLoadComplete()를 빈 함수로 재정의해도 마찬가지였다. 그래서 Firebug의 메시지에 의존하지 않고 패턴 찾아내기로 했다. 주목할만한 사실은 오류가 항상 발생하는 것은 아니라는 것이었다. 따라서, 오류를 발생시키는 원인은 “변경 영역”에 있을 것이라는 가설을 세우고 패턴을 찾기 위해 리프레시를 수도 없이 했다. 그리고 영역이 변경될 때 오류의 발생 여부를 파악해 정리하고보니 문제가 되는 것은 “메인 배너”라는 결론에 도달했다.

그림 4. 메인 배너 영역
문제는 메인 배너!
분명 페이지에서 메인 배너를 제거하고 나면 단 한번의 오류도 발생하지 않는다. 하지만 모든 메인 배너가 오류를 발생시키는 것은 아니다. 이미지가 메인 배너일 때는 오류가 전혀 발생하지 않으며, 배너가 플래시일 때만 간혹 발생한다. “간혹”이라는 말의 의미는 플래시임에도 분명 오류가 발생하지 않는 경우가 존재한다는 것이다.
확인 결과, 네이버의 메인 배너는 두 가지 타입의 스크립트를 사용하고 있는데, 하나는 그림 5와 같은 비교적 단순한 플래시 광고일 때만 사용하는 코드이고 다른 하나는 그림 6과 같이 마우스 오버 등 사용자의 액션을 필요로 하는 경우에 사용하는 스크립트이다. 이 중 에러가 나지 않는 것은 오히려 더 복잡한 액션을 필요로 하는 쪽이었다(처음에는 플래시의 문제인 줄 알고 디컴파일하려고 했었다).

그림 5. 단순한 플래시 광고의 스크립트

그림 6. 복잡한 플래시 광고의 스크립트
두 코드의 차이가 뭘까..하고 이리저리 테스트해보고 살펴보던 중 발견한 바로 저 것! document.domain! 설마…? 아무런 접근이 없는 상황에서도 단지 플래시가 존재한다는 이유만으로도 접근 권한 에러가…? 라는 의문을 가지고 그림 5의 코드에 그냥 그림 7처럼 document.domain만 삽입해보았다.
결과는…?

그림 7. document.domain 삽입
…잘 된다. 아는 것이 오히려 병이 된다고 했던가… 스크립트에서도 플래시에서도 다른 프레임간의 접근을 하지 않기 때문에 분명 다른 해결책이 있을 것이라고 생각했는데, 결국은 똑같은 방법. document.domain 이다. 아마도 어떤 이유에서인지 플래시 플레이어가 부모 객체에 접근을 시도하는 것 같다.
결론
uncaught exception : Location.toString 에러는 앞서 말했듯 동일근원 정책을 위반할 때 일어난다. 하지만, 플래시의 경우에는 명시적으로 동일근원 정책을 위반하지 않아도 에러가 발생한다. 이는 플래시 플레이어 내부에서 관련 사항을 위반하는 어떤 행위를 하기 때문이라고 생각한다. External Interface 관련 기능 때문일 수도 있고, 네트웍 접근을 위한 기능 때문일 수도 있다.
그래서 결론은? 결국 저 에러는 모두 document.domain 으로 통한다는 것이다. 또한, 한밤에 삽질하고 글 쓰느라 날려버린 4시간 30분이 너무 허무했다는 것이다. 그래도… 해결방법을 찾았으니 삽질의 보람이 아주 없진 않아서 다행이다.

그림 8. 결국 모든 길은 document.domain 으로 통하는 거다
도구들
이 글을 쓰기 위해 사용한 도구들입니다.
- Firebug : Firefox에서 JavaScript 등의 디버깅과 모니터링이 가능하도록 해주는 축복받은 확장기능
- FlashTracer : 혹시 Flash 관련 메시지가 나올까 하여… 실제로 사용은 안해봤음
- Download Embedded : 페이지내에 embed 된 파일을 다운로드 받을 수 있다.
- Fiddler2 : 로컬 프록시로, HTTP 패킷을 캡쳐해주고 Auto Responder 기능으로 원격지 파일을 로컬 파일로 대체할 수도 있다. 서버에 파일을 업로드 할 수 없거나 할 때에 좋음. .NET Framework 필요.
