1

SproutCore 1.8 に基づいて Web アプリを構築しようとしています。サーバーからデータを取得するために、アプリは別のドメインで実行されている REST Web サービスに対して CORS 要求を行います。

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

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

これは、Chrome、Safari、および Firefox ではうまく機能しますが、Internet Explorer 9 では機能しません。実際、IE9 では、SproutCore の内部要求実装で JavaScript エラー「アクセスが拒否されました」が発生します。エラーは次の行で発生します。

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

少し調査した結果、Microsoft が IE9 で CORS リクエスト専用の XDomainRequest オブジェクトを実装していることがわかりました。これらの行から推測すると、これは SproutCore ではサポートされていないようです (SproutCore ネイティブ リクエストの実装の選択)。

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

これは SproutCore の欠点ですか、それとも何か不足していますか? もしそうなら、私自身のリクエストの抽象化を書かずに問題を回避する方法について何か提案はありますか?

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

4

2 に答える 2

2

2 つのオプションがあります

1) Sproutcore 自体をハックします。追加してみることができます

function() {return new XDomainRequest(); }

違いのxhr輸送のリストに。最初に追加します。ブラウザで利用できる場合はそれが使用されます。そうでない場合、コードは他のオブジェクトにフォールバックします。

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

于 2012-04-24T12:10:36.040 に答える
1

私はhvgotcodesの提案に基づいてソリューションをすばやくコーディングしました。SC.XHRResponse以下のコードは、IE固有のXDomainRequestCORSリクエストを処理するために必要な機能を追加するサブクラスを実装しています。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;
  } 
});
于 2012-04-24T14:43:31.193 に答える