2012-04-24 4 views
1

SproutCore 1.8に基づくWebアプリケーションを構築しようとしています。サーバーからデータを取得するために、アプリケーションはCORS要求を別のドメインで実行されているREST Webサービスに送信します。IE9でSproutCoreを使用したクロスオリジンリクエスト

このためのコードは次のようになります。

var request = SC.Request.getUrl('http://example.com/some/path'); 
request.set('attachIdentifyingHeaders', NO);  
request.json().notify(this, this.didFetchData).send(); 

これはクロム、SafariやFirefoxで素晴らしい作品が、それは実際にはインターネットエクスプローラー9で動作しません、IE9は、JavaScriptエラーに実行されますSproutCoreの内部リクエストの実装で「アクセスが拒否されました」。私は、MicrosoftはIE9でCORS要求用の専用XDomainRequestオブジェクトを実装していることが分かったいくつかの短い調査の後

// initiate request. 
rawRequest.open(this.get('type'), this.get('address'), async); 

:エラーがこの行で発生します。私はこれらの行(SproutCoreネイティブ要求の実装の選択)から推測するように、これはSproutCoreによってサポートされていないようです:

return tryThese(
    function() { return new XMLHttpRequest(); }, 
    function() { return new ActiveXObject('Msxml2.XMLHTTP'); }, 
    function() { return new ActiveXObject('Microsoft.XMLHTTP'); } 
); 

これはSproutCoreの欠点ですか私は何かが足りないのですか?もしそうなら、私自身の要求抽象化を書かずに、どのようにしてこの問題を回避することができるかについての提案はありますか?

CORSは、私が作業している既存のサーバーインフラストラクチャの要件であることに注意してください。私はクライアントを提供しているサーバーと同じドメインにサービスを置くことも、リバースプロキシや同様のインフラストラクチャの問題を解決することもできません。

答えて

2

は、次の2つのオプション )Sproutcore自体をハックしています。あなたは差XHRの輸送手段のそのリストに

function() {return new XDomainRequest(); }

を追加してみてください。最初に追加してください。ブラウザ上で使用可能な場合は使用され、そうでない場合はコードが他のオブジェクトに戻されます。

2)SCソースを変更しない場合は、に拡張された独自のApp.CorsResponseクラスを作成できます。あなたの実装では、独自のcreateRequestメソッドを提供し、1)で述べたことを実行します。要求を作成するときはいつでも、responseClassをカスタム実装に指定します。

+0

ありがとう、これは私が期待していたものです。以前はオプション1が私の心に浮かんでいましたが、これは私がやるべき最後のものだと思います。私はオプション2を試してみます。 – starbugs

+0

それがどのように機能するか教えてください。 ;) – hvgotcodes

+0

両方のオプションが最後に同じ結果になることが分かります。 createRequestだけでなく、invokeTransportとfinishRequestもオーバーライドする必要があります。これにはエラー処理も含まれておらず、多くの繰り返しコードを意味します。 SC.Responseクラスでは、きれいな解決策を実現するために、さらに抽象化が必要になると思います。 XDomainRequestには同じ属性とコールバックがありません。 onreadystatechangeではなくonloadを実装する必要があり、異なるコールバックでエラーをチェックする必要があります。 stackoverflowが自分の質問に答えるとすぐにコードを投稿します。 – starbugs

1

私はすぐにhvgotcodesの提案に基づいてソリューションをコーディングしました。以下のコードは、IE固有のXDomainRequest CORS要求を処理するために必要な機能を追加するサブクラスSC.XHRResponseを実装しています。これは、XDomainRequestをまだ使用している場合、IEのエラーを処理しないことに注意してください。

MyApp.CorsRequest = SC.XHRResponse.extend({ 
    createRequest: function() { 
    function tryThese() { 
     for (var i=0; i < arguments.length; i++) { 
     try { 
      var item = arguments[i](); 
      return item; 
     } catch (e) {} 
     } 
     return NO; 
    } 

    return tryThese(
     function() { return new XDomainRequest(); }, 
     function() { return new XMLHttpRequest(); }, 
     function() { return new ActiveXObject('Msxml2.XMLHTTP'); }, 
     function() { return new ActiveXObject('Microsoft.XMLHTTP'); } 
    ); 
    }, 

    invokeTransport: function() { 
    var rawRequest, transport, handleReadyStateChange, async, headers; 

    rawRequest = this.createRequest(); 
    this.set('rawRequest', rawRequest); 

    // configure async callback - differs per browser... 
    async = !!this.getPath('request.isAsynchronous'); 

    if (async) { 
     if (!SC.browser.isIE && !SC.browser.isOpera) { 
     SC.Event.add(rawRequest, 'readystatechange', this, 
        this.finishRequest, rawRequest); 
     } else if(SC.browser.isIE) { 
      transport = this; 
     handleLoad = function() { 
      if (!transport) { return null; } 
      var ret = transport.finishRequest(); 
      if (ret) { transport = null; } 
      return ret; 
     }; 
     rawRequest.onload = handleLoad;   
     } else { 
     transport = this; 
     handleReadyStateChange = function() { 
      if (!transport) { return null; } 
      var ret = transport.finishRequest(); 
      if (ret) { transport = null; } 
      return ret; 
     }; 
     rawRequest.onreadystatechange = handleReadyStateChange; 
     } 
    } 

    // initiate request. 
    rawRequest.open(this.get('type'), this.get('address'), async); 

    // now send the actual request body - for sync requests browser will 
    // block here 
    rawRequest.send(this.getPath('request.encodedBody')) ; 
    if (!async) { this.finishRequest(); } 

    return rawRequest; 
    }, 

    finishRequest: function(evt) { 
    var rawRequest = this.get('rawRequest'), 
     readyState = rawRequest.readyState, 
     error, status, msg; 

     if (SC.browser.isIE) { 
      readyState = 4; 
      rawRequest.status = 200; 
     }  

    if (readyState === 4 && !this.get('timedOut')) { 
     this.receive(function(proceed) { 
     if (!proceed) { return; } 

     // collect the status and decide if we're in an error state or not 
     status = -1; 
     try { 
      status = rawRequest.status || 0; 
     } catch (e) {} 

     // if there was an error - setup error and save it 
     if ((status < 200) || (status >= 300)) { 

      try { 
      msg = rawRequest.statusText || ''; 
      } catch(e2) { 
      msg = ''; 
      } 

      error = SC.$error(msg || "HTTP Request failed", "Request", status); 
      error.set("errorValue", this) ; 
      this.set('isError', YES); 
      this.set('errorObject', error); 
     } 

     // set the status - this will trigger changes on related properties 
     this.set('status', status); 
     }, this); 

     // Avoid memory leaks 
     if (!SC.browser.isIE && !SC.browser.isOpera) { 
     SC.Event.remove(rawRequest, 'readystatechange', this, this.finishRequest); 
     } else { 
      if (window.XDomainRequest) 
       rawRequest.onload = null; 
      else 
      rawRequest.onreadystatechange = null; 
     } 

     return YES; 
    } 
    return NO; 
    } 
}); 
関連する問題