IE9のXDomainRequestでCORSするときにjQuery.noop使うと通信中断するバグ
IE9とjQueryの相性が悪い
今日はこれに悩まされました。ある特殊な状況で発生する発見しづらいバグです。以前もお伝えしましたが、重要なので繰り返しますと、IE 6,7はCORSに対応していません。IE 8,9は特殊対応しています。IE 10から正式対応する予定です。ここでいう、特殊対応とは、IE独自のオブジェクトを使ってクロスドメイン通信をします。XDomainRequestオブジェクトです。そして、こいつがやらかしましたw。常に動かないならまだしも、動いたり動かなかったり微妙な感じなのです。。。
jQueryでは空を表すためにjQuery.noopを使う
これはjQueryでイベントハンドラを書くときによく使う書き方で、ハンドラの中身に何も処理が無いのであれば、何も無いを明示するためにjQuery.noopを使っています。これは、function(){}と同じ事なのですが、XDomainRequestくんは違うものと認識してCORSを中断してしまいます。Nullと空文字みたいな感じかな。
IE 8,9でCORSをするためにxdr.jsを使ってjQueryを拡張する
xdr.jsは、jQueryの記述をほとんど変更することなく、IE 8,9に対してCORS命令を書く事ができる優れものの拡張表現です。
jQueryのロード後に宣言することで有効になります。基本的にはコレでOKです。
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script> <script src="xdr.js" type="text/javascript"></script>
jQuery.noop処理でCORS通信中断を回避
現在公開されているxdr.jsは、jQuery.noopによるバグ対策が施されていません。そこで、xdr.jsにパッチを充てました。
以下は修正したコードです。
if ( window.XDomainRequest ) { jQuery.ajaxTransport(function( s ) { if ( s.crossDomain && s.async ) { if ( s.timeout ) { s.xdrTimeout = s.timeout; delete s.timeout; } var xdr; return { send: function( _, complete ) { function callback( status, statusText, responses, responseHeaders ) { xdr.onload = xdr.onerror = xdr.ontimeout = function() { }; xdr = undefined; complete( status, statusText, responses, responseHeaders ); } xdr = new XDomainRequest(); xdr.onload = function() { callback( 200, "OK", { text: xdr.responseText }, "Content-Type: " + xdr.contentType ); }; xdr.onerror = function() { callback( 404, "Not Found" ); }; xdr.onprogress = function() { }; xdr.ontimeout = function() { callback( 0, "timeout" ); }; xdr.timeout = s.xdrTimeout || Number.MAX_VALUE; xdr.open( s.type, s.url ); xdr.send( ( s.hasContent && s.data ) || null ); }, abort: function() { if ( xdr ) { xdr.onerror = function() { }; xdr.abort(); } } }; } }); }
まとめ
エンジニアの肩書きがあるならソーシャルコーディングして片っ端から問題解決しようよぜー!