Почему некоторые междоменные JSON-запросы не выполняются, а другие нет? - PullRequest
5 голосов
/ 19 ноября 2010

У меня небольшие проблемы с пониманием безопасности в JSON, потому что часто вещи, которые теоретически не должны работать, по-видимому, делают.AFAIK, вызовы из сценария на странице, находящейся в домене A, не должны иметь возможность получать данные из домена B. Но в приведенном ниже коде вызовы одного внешнего домена не выполняются, тогда как другой проходит.И ни один из них не является упакованным вызовом JSON (jsonp).

Почему это так?Не следует ли запретить обоим проходить проверки безопасности браузера?Я получаю одинаковые результаты в Chrome и Firefox.Если я размещу приведенную ниже html-страницу на dropbox.com, Chrome выдаст мне следующее сообщение об ошибке:

XMLHttpRequest не может загрузить http://www.odinfond.no/rest/fund/calc/fundReturn?&id=300&oneTimeInvestment=100000&oneTimeInvestmentDate=2009-11-01&endDate=2010-11-01&currency=NOK. Источник http://dl.dropbox.com не разрешен Access-Control-Allow-Origin.

Ответ JSON, который я получил бы, если бы вызов прошел, можно увидеть, нажав по этой прямой ссылке .Вызов другой службы успешно завершен.Я размещаю приведенный ниже код на Dropbox. Попробуйте это здесь.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />

  <title>JSON/JSONP test</title>
  <script src="jquery.js" type="text/javascript"></script>
 </head>

 <body>
  <script>
   service = 'http://www.odinfond.no/rest/fund/calc/fundReturn?'; 
   parameters = { 
     id: '300',
     oneTimeInvestment:'100000',
     oneTimeInvestmentDate:'2009-11-01',
     endDate:'2010-11-01',
     currency:'NOK'
    }
   $.getJSON( service, parameters, function(data) {
    alert("Success"); 
   });

   service = 'http://ws.geonames.org/postalCodeLookupJSON?'
   parameters = {
    postalcode:1540,
    country:'NO'
   }
   $.getJSON(service, parameters, function(data) {
    alert(data.postalcodes[0].adminName2);
   });
  </script>
  <p>Use Firebug to see JSON response</p>
 </body>
</html>

Ответы [ 2 ]

6 голосов
/ 19 ноября 2010

Вы заметите, что рабочий запрос имеет заголовок ответа:

Access-Control-Allow-Origin: *

Это то, что освобождает браузер, чтобы сделать ответ доступным для сценария.(Обратите внимание, что запрос всегда сделан, одна и та же политика происхождения влияет только на то, доступен ли ответ сценарию или нет)

Если '*' является именем хоста, доступ толькоразрешено, если имя хоста текущего документа соответствует заголовку Access-Control-Allow-Origin

0 голосов
/ 19 ноября 2010

При просмотре исходного кода выясняется, что $ .ajax () обнаруживает удаленные URL-адреса и заменяет AJAX (XMLHttpRequest) ) со старыми добрыми тегами сценария:

    // Build temporary JSONP function
    if ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
        jsonp = s.jsonpCallback || ("jsonp" + jsc++);

        // Replace the =? sequence both in the query string and the data
        if ( s.data ) {
            s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
        }

        s.url = s.url.replace(jsre, "=" + jsonp + "$1");

        // We need to make sure
        // that a JSONP style response is executed properly
        s.dataType = "script";

        // Handle JSONP-style loading
        var customJsonp = window[ jsonp ];

        window[ jsonp ] = function( tmp ) {
            if ( jQuery.isFunction( customJsonp ) ) {
                customJsonp( tmp );

            } else {
                // Garbage collect
                window[ jsonp ] = undefined;

                try {
                    delete window[ jsonp ];
                } catch( jsonpError ) {}
            }

            data = tmp;
            jQuery.handleSuccess( s, xhr, status, data );
            jQuery.handleComplete( s, xhr, status, data );

            if ( head ) {
                head.removeChild( script );
            }
        };
    }

[...]

    // Matches an absolute URL, and saves the domain
    var parts = rurl.exec( s.url ),
        remote = parts && (parts[1] && parts[1].toLowerCase() !== location.protocol || parts[2].toLowerCase() !== location.host);

    // If we're requesting a remote document
    // and trying to load JSON or Script with a GET
    if ( s.dataType === "script" && type === "GET" && remote ) {
        var head = document.getElementsByTagName("head")[0] || document.documentElement;
        var script = document.createElement("script");
        if ( s.scriptCharset ) {
            script.charset = s.scriptCharset;
        }
        script.src = s.url;

        // Handle Script loading
        if ( !jsonp ) {
            var done = false;

            // Attach handlers for all browsers
            script.onload = script.onreadystatechange = function() {
                if ( !done && (!this.readyState ||
                        this.readyState === "loaded" || this.readyState === "complete") ) {
                    done = true;
                    jQuery.handleSuccess( s, xhr, status, data );
                    jQuery.handleComplete( s, xhr, status, data );

                    // Handle memory leak in IE
                    script.onload = script.onreadystatechange = null;
                    if ( head && script.parentNode ) {
                        head.removeChild( script );
                    }
                }
            };
        }

        // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
        // This arises when a base node is used (#2709 and #4378).
        head.insertBefore( script, head.firstChild );

        // We handle everything using the script element injection
        return undefined;
    }
...