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

479

Я разрабатываю страницу, которая извлекает изображения из Flickr и Panoramio через поддержку jQuery 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. Происхождение null не допускается через 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...
  });
});
  • 1
    Что означает URL выглядеть , что вы делаете запрос от? Например, это не динамически генерируемый iframe который вы iframe document.write ?
  • 5
    Можете ли вы опубликовать HTTP-ответ от запроса к каждой службе. Бьюсь об заклад, Panoramio не обслуживает Access-Control-Allow-Origin. См. W3.org/TR/cors для примеров.
Показать ещё 5 комментариев
Теги:
xmlhttprequest
cors
jsonp

16 ответов

427
Лучший ответ

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

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

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

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

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

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

  • Если вы пытаетесь использовать JSONP, убедитесь, что одно из следующего:
    • Вы используете $.get и установите dataType на jsonp.
    • Вы используете $.getJSON и включаете callback=? в URL.
  • Если вы пытаетесь выполнить междоменный XMLHttpRequest через CORS...
    • Убедитесь, что вы тестируете через http://. Скрипты, запущенные через file://, имеют ограниченную поддержку CORS.
    • Убедитесь, что браузер фактически поддерживает CORS. (Opera и Internet Explorer опаздывают на вечеринку)
  • 38
    Так каково решение этого?
  • 18
    Обратный вызов =? FTW
Показать ещё 17 комментариев
76

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

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

Подробнее в Перекрестный домен AJAX ou services WEB (на французском языке).

  • 13
    Как это сделать на обычном HTML-файле (без php)?
  • 1
    @Uri: Зависит от вашего HTTP-сервера. С Apache вам захочется заглянуть в mod_headers.
Показать ещё 4 комментария
66

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

cd project
python -m SimpleHTTPServer 8000

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

  • 1
    пока это здорово и работает, когда вы переходите на 0.0.0.0:8000 и пробуете POST запросы, вы получаете: code 501, message Unsupported method ('POST') для Google.
  • 0
    «Когда веб-сервер Python (например, cherrypy) говорит, что он работает на 0.0.0.0, это означает, что он прослушивает весь TCP-трафик, который заканчивается на этом компьютере, независимо от имени хоста или IP-адреса, который был запрошен». Поэтому, возможно, попробуйте опубликовать на localhost: 8000 stackoverflow.com/a/4341808/102022
Показать ещё 1 комментарий
19

Работает для меня в 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);
});

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


UPDATE:

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

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

  • 0
    Хм хорошо, позвольте мне попробовать еще раз. Я на другой версии Chrome, кстати, "6.0.472.51 бета".
  • 0
    Ваш код работал для меня. Я обновил свой вопрос с помощью кода, который решает проблему, хотя.
Показать ещё 4 комментария
8

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

5

Мы справились с ней через файл 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.

  • 1
    это не работает на Apache XAMPP. проблема все еще существует.
  • 1
    Это небезопасно. Смотрите здесь, почему; stackoverflow.com/questions/7564832/...
Показать ещё 1 комментарий
4

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

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

4

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

  • 2
    panoramio уже отправляет JSONP.
3

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

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-адресу, и тогда он работал нормально.

2

Не все серверы поддерживают 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;
    });
}
1

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

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

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

1

Я использую сервер 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/

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

0

Люди,

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

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

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

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

Спасибо, Andy

0

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

0

Я также получил ту же ошибку в 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]
0

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

Поэтому, немного поискав, я нашел это:

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

И тогда он будет работать на http://localhost:8000.

  • 1
    Хотя эта ссылка может ответить на вопрос, лучше включить здесь основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными в случае изменения связанной страницы. - Из обзора
  • 0
    Уточнил ссылку.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню