自宅サーバ-で開発したアプリをレンタルサーバーにインストールしたところ、IEからjQuery.uploadで画像をアップロードする処理が正常に動作しないという現象に遭遇しました。
不思議なことに、ChromeやFirefoxでは全く問題なく動作し、自宅サーバーに接続している限りはIEでも正常に動作します。
アプリの概要としては、よくあるユーザー情報登録系の処理で、利用者の写真をアップロードする際に、画面を更新せずともアップした写真が反映される仕組みの為にjQuery.uploadを使っていました。
また、この部分はライブラリ化されており、過去にも同じ仕組みを使ってプログラムを開発していたので、何が原因なのか分かりませんでした。
早速IEのデバッガを使って調査してみると、handleData関数の最初の処理で躓いていることが分かりました。
if ($.isXMLDoc(contents) || contents.XMLDocument) { return contents.XMLDocument || contents; }
このような処理があり、正常時はここのreturnでサーバーから返却されたXMLがコールバック関数に戻されるようになっています。
しかし、あるサーバーとIEを組み合わせると、このif文の条件に合致せず、その後処理となる戻ってきた文字列をXMLにパースするという処理に流れてしまっていることが判明しました。
(このことから、jQuery.uploadでアップロード処理までは完了しており、その戻り値となるXMLが正常に取得できないということが判明)
ここでパースされる文字列は、単純にサーバーから戻されたXML値が文字列になっているだけかと思ったのですが、それならXMLパース処理で正常にXMLに変換されエラーになることもありません。
ということで調べてみると、ここに渡される文字列は、XMLをIEで表示した際にIEが自動的に加工してしまうHTML形式になっていることも分かりました。
もちろんHTML文字列なので、XMLパース処理は失敗となります。
対応策として、HTML文字列となってしまったXMLから不要なタグを取り除き、XMLに戻してあげるしかありません。
XMLに格納されてくる文字については、こちらが作成したサーバー側の処理で返却する文字列なので、特殊文字等は存在しないことが保障されているので、次のような対応を取りました。
(parseXml関数内のXMLパース処理後に追加)
if (xml.xml == "") { text = text.stripTags(); text = unescapeHTML(text); text = replaceAll(text," ",""); text = replaceAll(text,"-<","<"); xml.loadXML(text); }
また、上記処理で使うunescapeHTML関数も以下のように定義しました。
function unescapeHTML(text) { var div = document.createElement('div'); div.innerHTML = text; return div.childNodes[0] ? (div.childNodes.length > 1 ? $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : div.childNodes[0].nodeValue) : ''; }
これによって、IEによってHTML化されたXMLを素のXMLに戻し、この文字列をXMLパースすることでXMLとして扱うことが出来るようになりました。
結果は正常に動作しました・・・が、どうもしっくりこない結果に終わりました。
そもそも、サーバが違う(細かく言えばPHPのマイナーバージョンが少し違う程度)でここまで違う動作をするもんかと・・・
IE9に搭載されている非常に強力なデバッガのおかげで無事(?)解決することができましたが、いまだに少し疑問の残る結果とまりました。