Ошибка XmlHttpRequest: нулевой источник не разрешен Access-Control-Allow-Origin

Я разрабатываю страницу, которая извлекает изображения из Flickr и Panoramio через поддержку jJuery AJAX.

Сторона Flickr работает нормально, но когда я пытаюсь $.get(url, callback) из Panoramio я вижу ошибку в консоли Chrome:

XMLHttpRequest не может загрузить http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&callback=processImages&minx=-30&miny=0&maxx=0&maxy=150. Нулевой источник не разрешен Access-Control-Allow-Origin.

Если я запрашиваю этот URL из браузера напрямую, он работает нормально. Что происходит, и могу ли я обойти это? Я неправильно составляю свой запрос, или это то, что Panoramio делает, чтобы мешать тому, что я пытаюсь сделать?

Google не обнаружил никаких полезных совпадений в сообщении об ошибке.

РЕДАКТИРОВАТЬ

Вот пример кода, который показывает проблему:

$().ready(function () {
  var url = 'http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&callback=processImages&minx=-30&miny=0&maxx=0&maxy=150';

  $.get(url, function (jsonp) {
    var processImages = function (data) {
      alert('ok');
    };

    eval(jsonp);
  });
});

Вы можете запустить пример онлайн.

РЕДАКТИРОВАТЬ 2

Спасибо Дарину за помощь в этом. ВЫШЕ КОД НЕПРАВИЛЬНО. Используйте это вместо:

$().ready(function () {
  var url = 'http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&minx=-30&miny=0&maxx=0&maxy=150&callback=?';

  $.get(url, function (data) {
    // can use 'data' in here...
  });
});

16 ответов

Решение

Для протокола, насколько я могу судить, у вас было две проблемы:

  1. Вы не передавали спецификатор типа "jsonp" $.get так что он использовал обычный XMLHttpRequest. Тем не менее, ваш браузер поддерживает CORS (Cross-Origin Resource Sharing), чтобы разрешить междоменный XMLHttpRequest, если сервер его подтвердил. Вот где Access-Control-Allow-Origin пришел заголовок

  2. Я полагаю, вы упомянули, что запускаете его из файла:// URL. Есть два способа для заголовков CORS сигнализировать, что междоменный XHR в порядке. Один, чтобы отправить Access-Control-Allow-Origin: * (что, если вы достигли Flickr через $.get, они, должно быть, делали), в то время как другой должен был повторить содержание Origin заголовок. Тем не мение, file:// URL выдают ноль Origin который не может быть авторизован через echo-back.

Первый был решен окольным путем предложением Дарина использовать $.getJSON, Это делает немного волшебства, чтобы изменить тип запроса со своего значения по умолчанию "json" на "jsonp", если он видит подстроку callback=? в URL.

Это решило второе, больше не пытаясь выполнить запрос CORS от file:// URL.

Чтобы уточнить для других людей, вот простые инструкции по устранению неполадок:

  1. Если вы пытаетесь использовать JSONP, убедитесь, что имеет место одно из следующих действий:
    • Вы используете $.get и установить dataTypeв jsonp,
    • Вы используете $.getJSON и включены callback=? в URL.
  2. Если вы пытаетесь сделать междоменный XMLHttpRequest через CORS...
    1. Убедитесь, что вы тестируете через http://, Скрипты, работающие через file:// ограниченная поддержка CORS.
    2. Убедитесь, что браузер действительно поддерживает CORS. (Opera и Internet Explorer опаздывают на вечеринку)

Возможно, вам нужно добавить HEADER в ваш вызываемый скрипт, вот что я должен был сделать в PHP:

header('Access-Control-Allow-Origin: *');

Более подробная информация в кросс-домене AJAX ou services WEB (на французском языке).

Для простого HTML-проекта:

cd project
python -m SimpleHTTPServer 8000

Затем просмотрите свой файл.

У меня работает в Google Chrome v5.0.375.127 (я получаю предупреждение):

$.get('http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&callback=?&minx=-30&miny=0&maxx=0&maxy=150',
function(json) {
    alert(json.photos[1].photoUrl);
});

Также я бы порекомендовал вам использовать $.getJSON() Вместо этого метод, так как предыдущий не работает на IE8 (по крайней мере, на моей машине):

$.getJSON('http://www.panoramio.com/wapi/data/get_photos?v=1&key=dummykey&tag=test&offset=0&length=20&callback=?&minx=-30&miny=0&maxx=0&maxy=150', 
function(json) {
    alert(json.photos[1].photoUrl);
});

Вы можете попробовать это онлайн здесь.


ОБНОВИТЬ:

Теперь, когда вы показали свой код, я вижу проблему с ним. У вас есть как анонимная, так и встроенная функция, но обе они будут вызваны processImages, Вот как работает поддержка JSONP в jQuery. Обратите внимание, как я определяю callback=? так что вы можете использовать анонимную функцию. Вы можете прочитать больше об этом в документации.

Еще одно замечание, что вы не должны звонить Eval. Параметр, переданный вашей анонимной функции, будет уже проанализирован в JSON jQuery.

Пока запрашиваемый сервер поддерживает формат данных JSON, используйте интерфейс JSONP (JSON Padding). Это позволяет вам делать внешние запросы домена без прокси-серверов или причудливых заголовков.

Если вы делаете локальное тестирование или вызываете файл из чего-то вроде file:// тогда вам нужно отключить безопасность браузера.

На MAC:open -a Google\ Chrome --args --disable-web-security

Это та же политика происхождения, вы должны использовать интерфейс JSON-P или прокси, работающий на том же хосте.

Нам удалось через http.conf файл (отредактировал и перезапустил службу HTTP):

<Directory "/home/the directory_where_your_serverside_pages_is">
    Header set Access-Control-Allow-Origin "*"
    AllowOverride all
    Order allow,deny
    Allow from all
</Directory>

в Header set Access-Control-Allow-Origin "*"Вы можете указать точный URL.

В моем случае, тот же код отлично работал на Firefox, но не на Google Chrome. Консоль JavaScript в Google Chrome сказала:

XMLHttpRequest cannot load http://www.xyz.com/getZipInfo.php?zip=11234. 
Origin http://xyz.com is not allowed by Access-Control-Allow-Origin.
Refused to get unsafe header "X-JSON"

Мне пришлось отбросить часть www URL-адреса Ajax, чтобы он соответствовал исходному URL-адресу, и тогда он работал нормально.

В качестве заключительного замечания в документации Mozilla прямо сказано, что

Вышеприведенный пример потерпит неудачу, если заголовок будет подстановочным символом: Access-Control-Allow-Origin: *. Поскольку Access-Control-Allow-Origin явно упоминает http://foo.example/, контент с удостоверением личности возвращается в вызывающий веб-контент.

Как следствие, это не просто плохая практика использовать "*". Просто не работает:)

Не все серверы поддерживают JSONP. Это требует, чтобы сервер установил функцию обратного вызова в своих результатах. Я использую это для получения ответов json с сайтов, которые возвращают чистый json, но не поддерживают jsonp:

function AjaxFeed(){

    return $.ajax({
        url:            'http://somesite.com/somejsonfile.php',
        data:           {something: true},
        dataType:       'jsonp',

        /* Very important */
        contentType:    'application/json',
    });
}

function GetData() {
    AjaxFeed()

    /* Everything worked okay. Hooray */
    .done(function(data){
        return data;
    })

    /* Okay jQuery is stupid manually fix things */
    .fail(function(jqXHR) {

        /* Build HTML and update */
        var data = jQuery.parseJSON(jqXHR.responseText);

        return data;
    });
}

Я использую сервер Apache, поэтому я использовал модуль mod_proxy. Включить модули:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Затем добавьте:

ProxyPass /your-proxy-url/ http://service-url:serviceport/

Наконец, передайте proxy-url в ваш скрипт.

Для PHP - эта работа для меня в Chrome, safari и firefox

https://w3c.github.io/webappsec-cors-for-developers/

header('Access-Control-Allow-Origin: null');

используя axios, вызывайте php live services с file://

Я также получил ту же ошибку в Chrome (я не тестировал другие браузеры). Это было связано с тем, что я перешел на domain.com вместо www.domain.com. Немного странно, но я мог бы решить проблему, добавив следующие строки в.htaccess. Он перенаправляет domain.com на www.domain.com, и проблема была решена. Я - ленивый посетитель, поэтому почти никогда не набираю www, но в некоторых случаях это требуется.

RewriteEngine on
RewriteCond %{HTTP_HOST} ^domain\.com$ [NC]
RewriteRule ^(.*)$ http://www.domain.com/$1 [R=301,L]

Убедитесь, что вы используете последнюю версию JQuery. Мы столкнулись с этой ошибкой для JQuery 1.10.2, и ошибка была устранена после использования JQuery 1.11.1

Folks,

Я столкнулся с аналогичной проблемой. Но с помощью Fiddler я смог разобраться в проблеме. Проблема заключается в том, что URL-адрес клиента, настроенный в реализации CORS на стороне веб-API, не должен иметь косую черту в конце. После отправки запроса через Google Chrome и проверки вкладки TextView в разделе " Заголовки " Fiddler в сообщении об ошибке говорится что-то вроде этого:

* "Указанный источник политики your_client_url:/'недопустим. Он не может заканчиваться косой чертой."

Это очень странно, потому что он работал без проблем в Internet Explorer, но доставлял мне головную боль при тестировании с использованием Google Chrome.

Я удалил косую черту в коде CORS и перекомпилировал Web API, и теперь API доступен через Chrome и Internet Explorer без каких-либо проблем. Пожалуйста, дайте этому шанс.

Спасибо энди

В решении, опубликованном CodeGroover выше, есть небольшая проблема, когда при изменении файла вам придется перезапустить сервер, чтобы фактически использовать обновленный файл (по крайней мере, в моем случае).

В поисках немного, я нашел этот, чтобы использовать:

sudo npm -g install simple-http-server # to install
nserver # to use

И тогда он будет служить в http://localhost:8000,

Другие вопросы по тегам