포럼
한글도메인에서의 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
댓글 13
-
무얼까2
2015.01.09 13:34
-
시니시즘
2015.01.09 13:45
IE9가 잘못했네요 (농담)
-
무얼까2
2015.01.09 18:53
^^
-
무얼까2
2015.01.09 19:09
xe의 ajax 부분에 문제가 있다.
그게 어딘지는 아직 찾지 못했지만, 한글도메인이기 때문에 ajax가 안되는 것은 아니다.
IE라서 안되는 것도 아니다.
일반 html 하나 만들고, 기본 $.ajax 로 테스트 해보면 전혀 문제 없이 잘 된다.
예를 들어, 아래와 같이 js 파일에 'location.host'로 url 경로 지정해서 다른 디렉토리에 있는 것 불러와도 잘 된다.
$('#post2').click(function() { $.ajax({ url:'http://'+location.host+'/layouts/ajax2.php', type:'POST', dataType: 'xml', success: function(data){ $('#dictionary').empty(); $.each($(data).find('entry'), function(){ var $entry = $(this); var html ='<div class="entry">'; html +='<h3 class="term">'+ $entry.attr('term'); +'</h3>'; html +='<div class="part">'+ $entry.attr('part'); +'</div>'; html +='<div class="definition">'+ $entry.text()+'</div>'; html +='</div>'; $('#dictionary').append(html); });// end each }// end });// end ajax return false; });
IE9 콘솔에 location.host 찍어보면, www.한글도메인.com 이라고 뜬다.
-
무얼까2
2015.01.09 23:30
xe 기본 jquery에 문제가 있지 않을까 해서,
/common/js/jquery.js 를 jquery-1.10.2.js 로 교체하고,
이러면서 빠진 jquery migrate는
/classes/display/HTMLDisplayHandler.php 의 개발모드 쪽 jquery.js 아래에 $oContext->loadFile(array('./common/js/jquery-migrate-1.2.1.js', 'head', '', -109000), true); 를 추가.
이 상태로 글 등록을 하면, 콘솔 창에 xhr.statusText 값이 'No Transport'라고 뜬다. 크로스도메인으로 인식.
xml_handler.js 의 $.ajax 위에 $.support.cors = true; 를 넣으면 'No Transport'는 뜨지 않고, '잘못된 요청'이라는 메시지가 뜬다.
($.support.cors = true; 는 크로스도메인을 허용시키는 것으로 지금은 테스트 중이라 썼지만, 실제로는 xss 위험)
이 메시지를 띄우는 부분은 document.controller.php의 insertDocument 에 있는 checkCSRF 이다.
이것을 해결하는 것이 바로 미솔님이 올리신 punycode 변환 라이브러리.
func.inc.php의 checkCSRF 함수에 punycode 라이브러리를 적용하면 글 등록이 정상으로 된다.
하지만, '이 페이지를 나가시겠습니까?'란 메시지를 띄운다.
대충 짐작이 가는 부분이고.
================================
기록 겸 해서 남기느라 말이 짧습니다.;;
xe 기본 jquery 버전이 2.0.3이더군요. 교체한 1.10.2와 비교해보니, 이유는 모르겠지만 XMLHttpRequest에서 IE를 지원하는 ActiveXObject( "Microsoft.XMLDOM" ) 부분이 없습니다.
교체 전에는 xhr.status 에 500 이라고 뜨고, xhr.statusText는 무반응이었는데, 교체 후 No Transport 라는 친절한 문구를 띄웁니다.
교체 후 변화 가운데 하나는, 관리자 페이지에서 '캐시파일 재생성'이 정상 작동한다는 것입니다.
(물론, waiting message 관련한 주석을 풀면 도로 TypeError 'css'를 뱉어 내구요.)
또한, 게시판 분류 관리에서 뜨지 않던 카테고리도 뜨고요.
그리고, 회원 가입시 무반응이던 value 체크가 제대로 됩니다.
아직 사이트 메뉴 편집 쪽에서는 콘솔에 '로그: error'을 띄우지만, 문제 해결에 가까이 간 듯 합니다.
이제 $.support.cors = true; 를 쓰지 않아도, 게시글 등록이 되게끔 해결하면 될 것 같습니다.
xe의 ajax 쪽에서 무언가 크로스도메인으로 인식하는데, 위에서도 말했듯이, 한글도메인이라서, IE라서가 아닙니다.
xe와 독립된 일반 페이지 만들고 ajax 해보면 잘 됩니다.
xe의 ajax를 뜯어 봐야 겠습니다. 오늘은 여기까지 하고 일단 잡니다.
-----------------
자기 전에 잠깐 XP 띄우고 IE7에서 테스트 해봤습니다.
됩니다.(카테고리 빼고;)
-----------------
포럼이 개인 게시판도 아닌데 이렇듯 계속 답글로 기록을 남기는 것은, 여러분의 도움을 구하는 것이기도 합니다.
물론 한글도메인을 가진 테스트 환경이 있으신 분은 많지 않을테지요.
그러나, 제가 테스트 과정에서 알아낸 것들을 자세히 올리는 이유는, 이걸 보시고 제게 해결의 실마리라도 주셨으면 하는 바람에서 입니다.
전 xe 구조도 잘 모르고, 자바스크립트도 잘 모릅니다. debugPrint를 곳곳에 배치해서 문제가 발생하는 쪽을 찾고, 구글을 뒤지고, 짐작에 따라 이래저래 바꿔도 봅니다. 그렇다보니 시간도 오래 걸리네요.
한글도메인에서도 당당하게 XE를 쓸 수 있길 바라며, 여러분의 도움을 바랍니다.
-
시니시즘
2015.01.10 02:50
http://pat.im/921 이 글은 참고해보셨는지요. 아마 님 스스로 해결이 힘든 문제인 것 같습니다...
-
무얼까2
2015.01.10 09:13
네. 얼마 전 사이트 작업 할 때 진작에 본 글입니다.
그 글의 핵심은, xe만 안된다 입니다.
-
시니시즘
2015.01.10 03:01
그냥 문득 드는 생각인데, 실제 "영문 홈페이지 도메인"을 하나 준비하시고, "한글 홈페이지 도메인"을 준비하신 뒤에 .htaccess 파일로 rewrite를 시키시는건 어떤지요? http://한글.com/bbs에 접속하면 도메인은 유지한채 http://foobar.com/bbs를 보여지게 하는 방법입니다. 2개의 도메인에 관한 부분은 제가 테스트를 못해봤는데 아래 링크 한번 참조하시고 시도해보시길 바랍니다. 도움이 됬으면 좋겠네요.
http://www.inmotionhosting.com/support/website/htaccess/redirect-without-changing-url
-
무얼까2
2015.01.10 09:44
위 답글과 마찬가지로, 얼마 전 작업했던 사이트(그누4->XE)가 한글도메인 2개, 영문도메인2개를 보유하고 있었습니다.
그 때 한글도메인에 xe 설치를 처음 해봤고, 그동안 몰랐던 문제를 깨닫게 됐습니다.
아무리 해봐도 안되길래 결국 말씀하신 것처럼 .htaccess에서 영문도메인으로 리다이렉팅 시키는 것으로 일단 마무리 지었습니다. - 참고로, 리다이렉팅은 한글도메인(또는 서브도메인)을 유지한 채가 아니라, 한글도메인(또는 서브도메인)으로 접속한 것을 특정 도메인으로 바꿔버리는 것입니다. 이 방법은 여러 도메인을 쓸 때 로그인 유지 기능이 제대로 작동하는데 도움이 됩니다. 로그인 유지 관련해서는 몇몇 방법이 또 있구요. -
하지만, '전에는 잘 됐는데, 지금은 왜 이런 문제가 생기냐?'란 클라이언트의 한 마디에 정말 쪽 팔리더군요.
제가 생각하는 CMS는 어떤 운영체제건 어지간한 웹브라우저에서건 어떤 도메인이건, 기본 기능이랄 수있는 회원관리와 게시판은 이용할 수 있어야 한다는 것입니다. 그 외 특별한 기능(예: html5, css3 따위)은 그다음 문제고요.
그리고, XE는 설치 과정부터 다국어를 지원합니다.
한글도메인은 곧 IDN(국제도메인)입니다. 외국에서 XE로 홈페이지를 만들 때, 몇몇은 그들의 국제도메인을 쓰려 했다가 저 처럼 포기하겠지요. - IDN을 포기하던가, XE를 포기하던가 -
이러던 차에 미솔님께서 올리신 pubycode 라이브러리를 보고 희망을 갖게 됐습니다. 그러나, 그 라이브러리만 적용하면 IE11 만 됩니다.(IE10은 갖고 있질 않아 모르겠고요) IE789에서는 여전히 안됩니다.
하지만, 지금 이래저래 테스트하면서 한글도메인의 IE에서 글쓰기가 됩니다. 심지어 IE7에서도 됩니다.
그동안 안되던 대부분 기능이 됩니다.
완전히 해결할 수 있을지는 모르겠지만, 좀 더 지켜봐 주십시오.
답변 감사합니다.
-
시니시즘
2015.01.11 02:56
참고로, 리다이렉팅은 한글도메인(또는 서브도메인)을 유지한 채가 아니라, 한글도메인(또는 서브도메인)으로 접속한 것을 특정 도메인으로 바꿔버리는 것입니다.
라고 하셨는데 저는 rewrite를 말씀 드린 겁니다. rewrite는 도메인을 유지한채 다른 경로의 페이지를 로딩할 수 있는 걸 의미합니다. 이 부분은 잘 모르시는 것 같군요 ㅎㅎ
-
무얼까2
2015.01.11 09:13
아. 그건 몰랐습니다.
제가 잘못 알고 있었군요.
더 공부해야겠습니다. 감사합니다. ^^
-
misol
2015.01.10 23:20
오옹!
제가 관심을 깨웠다니 기쁩니다! -
무얼까2
2015.01.11 09:12
네. 덕분에 xe 구석구석 이 잡듯 돌아댕겼습니다. ㅎ
엉뚱한 곳을 헤매기도 했지만, 결국 도메인 관련 함수 세 곳과 defaut_url 저장, setQuery만 수정하면 되는 간단한 거였습니다.
미솔님께서 올리신 idna 라이브러리와 글 덕분입니다.
파일 업로드까지 해결하고 또 보여드리겠습니다.
정말 감사합니다.
write_form.html 에서 onsubmit="return procFilter(this, window.insert)" 를 지우고,
<input type="hidden" name="module" value="board" />
<input type="hidden" name="act" value="procBoardInsertDocument" />
module과 act를 직접 지정하면 정상 등록 됨.(물론 ajax가 아니라 직접 post로 보내니 당연하겠지요.;)
만약, procFilter를 적용하면, xml.status는 500을 내놓고, 피들러에서 찍어보면 잘못된 요청이라는 메시지가 뜨네요.
procFilter는 어디에 있을까요?
얘를 좀 뒤져 봐야 할텐데요.