포럼
한글도메인에서의 ajax 테스트 중.(해결)
2015.01.09 13:27
- 사용 브라우저 : IE9
- XE : 1.7.9
답답해서 이래저래 해보던 가운데 특이한 것이 발견 되었습니다.
한글도메인에서 관리자 페이지의 '캐시파일 재생성' 같은 걸 눌러도 TypeError 'css'가 나타났는데, 이 메시지가 서버에 전송중이라는 메시지가 나타나기도 전에 나오는 겁니다.
혹시나 하고 xml_handler.js의 exec_xml에서 waiting message 관련한걸 주석처리 하니 더 이상 TypeError 메시지는 나타나지 않고, 대신 1.7.9 기준으로 IE9 에서 F12 개발자 도구 콘솔 창에 '로그 : error' 라는 짧은 메시지가 뜹니다.
글쓰기를 해도 TypeError는 뜨지 않지만, 마찬가지로 등록 버튼을 눌렀을 때 '로그 : error'가 찍히고, 자동 저장될 때도 찍힙니다.
미솔님께서 올리신 파일을 적용하든 안하든 똑같고요.
어쨌든, 주석 처리하기 전에는 콘솔 창이 무반응이었는데, 이젠 최소한 아작스까지 넘어간 후 에러 메시지를 보여줍니다.
또한, 사이트 메뉴 편집을 들어가면 아무 메뉴도 뜨지 않는데, 소스보기를 해보면 메뉴가 표시 될 자리에 템플릿 코드가 그대로 나타 납니다.
예)
<section class="mapi" id="siteMapTree"> <script id="tmpl_menuTree" type="text/x-jquery-tmpl"> <ul> {{html Nodes}} </ul> </script> <script id="tmpl_menuTreeNode" type="text/x-jquery-tmpl"> <li id="menu${MenuId}"> <a href="#" data-param='{ "sMenuId":"${MenuId}" }'>${MenuTitleWithHome}</a> {{html SubTree}} </li> </script> <script id="tmpl_menuSelector_menuTree" type="text/x-jquery-tmpl"> <ul> {{html Nodes}} </ul> </script> <script id="tmpl_menuSelector_menuTreeNode" type="text/x-jquery-tmpl"> <li> <a href="#" class="_nodeType_${NodeType} _menu_url_${MenuUrl}" data-param='{ "sMenuId":"${MenuId}", "sMenuUrl":"${MenuUrl}", "sMenuTitle":"${MenuTitle}" }'>${MenuTitle}</a> {{html SubTree}} </li> </script> </section>
뭔가 dom이라든가, ajax 처리 단에서 문제가 있는 듯 한데, 제 짧은 지식으로는 여기까지가 한계입니다.
(추가: 주석처리 했어도, 크롬과 파폭은 전송 중 메시지가 나타나지 않을 뿐 정상 처리됩니다.)
======================================================================
xe 기본 jquery를 1.10.2로 바꿨다가 원래 것인 2.0.3으로 되돌렸습니다.
잘 되더군요.
IE 지원하는 ActiveXObject( "Microsoft.XMLDOM" ) 도 있구요.
여하튼, jquery의 문제가 아니었습니다.
아래 답글에서 했던 것처럼 하고 최종 단계에서 문제가 생겼는데, XE 페이지 소스에 삽입되는 js 변수 request_uri, current_url 이 punycode 였다는 것입니다.
이것 때문에 js는 location.href 에는 한글인데, 저 변수는 punycode이니 크로스브라우징으로 판단한 것입니다.
(이렇게 판단하는 것 역시 IE의 js 해석에 따른 차이라고 볼 수 있습니다.)
위험한 $.support.cors=true;를 쓰지 않고 해결 할 방법은 두 가지 입니다.
1. $.ajax 쪽에서 js 변수 request_uri 같은 것이 punycode('xn--'로 시작)이면, request_uri를 location.host 같은 것을 써서 대체.
2. 애초에 js 변수 request_uri 등을 한글도메인으로 나타나게 하거나.
전 2번을 택했습니다.
근본을 해결하고자 함이었죠.
처음부터 다시 정리하면,
1. 미솔님이 올리신 idna 라이브러리가 필요합니다. https://github.com/xpressengine/xe-core/pull/1120
(php 5.3 이상이라면, PHP에 INTL extension 을 설치해서 idn_to_utf8 함수를 써도 됩니다.)
2. 미솔님이 올리신 방법 가운데, func.inc.php는 수정하지 않고, install.admin.controller.php만 수정합니다.
(default_url은 punycode로 써야 파폭이나 모바일에서 에러가 나지 않습니다.)
$default_url = Context::get('default_url'); if($default_url && strncasecmp('http://', $default_url, 7) !== 0 && strncasecmp('https://', $default_url, 8) !== 0) $default_url = 'http://'.$default_url; if($default_url && substr($default_url, -1) !== '/') $default_url = $default_url.'/'; /* convert NON Alphabet URL to punycode URL - Alphabet URL will not be changed */ require_once(_XE_PATH_ . 'libs/idna_convert/idna_convert.class.php'); $IDN = new idna_convert(array('idn_version' => 2008)); $default_url = $IDN->encode($default_url);
3. Context.class.php에서 세 개의 함수를 수정했습니다.
$db_info = self::getDBInfo(); if( strpos($db_info->default_url, 'xn--') !== FALSE && ( strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE || strpos($_SERVER['HTTP_USER_AGENT'], 'Trident') !== FALSE ) ) { require_once(_XE_PATH_ . 'libs/idna_convert/idna_convert.class.php'); $IDN = new idna_convert(array('idn_version' => 2008)); $IDN_Domain = $IDN->decode($db_info->default_url); } else { $IDN_Domain = $db_info->default_url; } return $IDN_Domain;
if( strpos($_SERVER['HTTP_HOST'], 'xn--') !== FALSE && ( strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE || strpos($_SERVER['HTTP_USER_AGENT'], 'Trident') !== FALSE ) ) { require_once(_XE_PATH_ . 'libs/idna_convert/idna_convert.class.php'); $IDN = new idna_convert(array('idn_version' => 2008)); $IDN_Domain = $IDN->decode($_SERVER['HTTP_HOST']); } else { $IDN_Domain = $_SERVER['HTTP_HOST']; } // if $domain is set, compare current URL. If they are same, remove the domain, otherwise link to the domain. if($domain) { $domain_info = parse_url($domain); if(is_null($current_info))
if($domain) { $target_url = trim($domain); if(substr_compare($target_url, '/', -1) !== 0) { $target_url.= '/'; } } else { if( strpos($_SERVER['HTTP_HOST'], 'xn--') !== FALSE && ( strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE || strpos($_SERVER['HTTP_USER_AGENT'], 'Trident') !== FALSE ) ) { require_once(_XE_PATH_ . 'libs/idna_convert/idna_convert.class.php'); $IDN = new idna_convert(array('idn_version' => 2008)); $IDN_Domain = $IDN->decode($_SERVER['HTTP_HOST']); } else { $IDN_Domain = $_SERVER['HTTP_HOST']; } $target_url = $IDN_Domain . getScriptPath(); } $url_info = parse_url('http://' . $target_url);
( strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE || strpos($_SERVER['HTTP_USER_AGENT'], 'Trident') !== FALSE ) 를 적용해서 IE에서만 동작하게 하지 않으면, 파폭이나 모바일에서 잘못된 요청 메시지가 뜹니다.
(크롬은 이딴게 있거나 말거나 어느 상황에서도 실행 됩니다.;;)
4. 여기까지 하면 그동안 나타나던 TypeError도 나타나지 않고 모든 기능이 정상입니다. 단, 글쓰기에서 ajax 완료 후 리턴할 때 url이 인코딩 되서 엉뚱한 주소로 바뀝니다. 이유는, setQuery 프로토타입 선언부에서 url을 통으로 인코딩 하기 때문입니다.
따라서, /common/js/common.js 에서 setQuery 프로토타입 선언부에서 domain 뒤쪽 query_string만 인코딩 되도록 수정합니다.
String.prototype.setQuery = function(key, val) { var loc = isSameUrl(this, window.location.href) ? current_url : this; var idx = loc.indexOf('?'); var uri = loc.replace(/#$/, ''); var act, re, v, toReplace; if (typeof(val)=='undefined') val = ''; if (idx != -1) { var query_string = uri.substr(idx+1, loc.length), args = {}, q_list = []; uri = loc.substr(0, idx); query_string.replace(/([^=]+)=([^&]*)(&|$)/g, function(all,key,val) { args[key] = val; }); args[key] = val; for (var prop in args) { if (!args.hasOwnProperty(prop)) continue; if (!(v = String(args[prop]).trim())) continue; q_list.push(prop+'='+decodeURI(v)); } query_string = q_list.join('&'); uri = uri+(query_string?'?'+encodeURI(query_string):''); } else { if (String(val).trim()) { query_string = '?'+key+'='+val; uri = uri+encodeURI(query_string); } } re = /^https:\/\/([^:\/]+)(:\d+|)/i; if (re.test(uri)) { toReplace = 'http://'+RegExp.$1; if (window.http_port && http_port != 80) toReplace += ':' + http_port; uri = uri.replace(re, toReplace); } var bUseSSL = !!window.enforce_ssl; if (!bUseSSL && isArray(window.ssl_actions) && (act=uri.getQuery('act'))) { for (var i=0,c=ssl_actions.length; i < c; i++) { if (ssl_actions[i] === act) { bUseSSL = true; break; } } } re = /http:\/\/([^:\/]+)(:\d+|)/i; if (bUseSSL && re.test(uri)) { toReplace = 'https://'+RegExp.$1; if (window.https_port && https_port != 443) toReplace += ':' + https_port; uri = uri.replace(re, toReplace); } // insert index.php if it isn't included uri = uri.replace(/\/(index\.php)?\?/, '/index.php?'); return uri; };
5. 끝났습니다.
결론은, IE는 그냥 한글로 돌아 댕기게 하면 된다는 것입니다.
이제 파일 업로드만 해결하면 되는데, swfuploader의 문제라고 하니, 일단 살펴 봐야 겠습니다.
플래시 파일 내부에서의 문제라면 제가 손 볼 수 없는 노릇이고, XE 팀에서 나서 준다면 해결책이 있지 않을까 합니다.
swfupload.org 운영 안하는 군요.;; swfupload는 버려야 할 듯.
fine uploader 라는게 맘에 드네요. xe 에디터와 어울리지는 않을 것 같지만 함 붙여 봐야 겠습니다.
6. SSL은 테스트 못했습니다. 조만간 신청해서 테스트해 볼 것입니다.
7. 테스트 브라우저
Windows XP IE7
Windows XP IE8
Windows 7 IE9
Windows 7 IE11
Windows 7 FF 34.0
Windows 7 Chrome 39.0.2171.95 m
Windows 7 Safari 5.1.7
Windows 7 Opera 26.0.1656.60
Mobile : 5~6년 된 Vega X+, model: IM-A725L, Android: 2.2.1
============
아참. 테스트 url : www.무얼까.com
-------------------
추가) idn converter에는 js 도 있습니다.
https://github.com/bestiejs/punycode.js