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


550

Я разрабатываю страницу, которая извлекает изображения из 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...
  });
});

1
Что делает URL выглядеть , что вы делаете запрос от ? Например, это не iframeто, что вы динамически генерируете document.write?
Пекка

5
Можете ли вы опубликовать HTTP-ответ от запроса к каждой службе. Бьюсь об заклад, Panoramio не обслуживает Access-Control-Allow-Origin. Смотрите w3.org/TR/cors для примеров.
Кевин Хакансон

2
@Kevin, вам не нужны эти заголовки, если сервер отправляет JSONP.
Дарин Димитров

@Pekka, я сейчас запускаю страницу с моего локального компьютера ( file:///C:/). Нет iframeучаствует.
Дрю Ноакс

1
@ Что случилось, если запустить его с http-адреса? Это не должно иметь никакого значения, а просто исключает возможность.
Пекка

Ответы:


423

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

  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 опаздывают на вечеринку)

45
Так каково решение этого?
jQuerybeast

19
Обратный вызов =? FTW
Тим

10
Некоторые браузеры, такие как chrome, разрешают CORS, если они запускаются с параметром --allow-file-access-from-files
echox

1
callback=?не работал для меня, но jsonp=?сделал. Любое объяснение этому?
crunkchitis

1
Нужно ли устанавливать веб-сервер для тестирования через http://? Или есть способ просто открыть файл с использованием этого протокола?
Уилл Сьюэлл,

76

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

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

Подробнее о кросс-домене AJAX ou services WEB (на французском).


1
@Uri: Зависит от вашего HTTP-сервера. С Apache вы захотите заглянуть в mod_headers.
Ssokolow

4
@Uri <meta http-equ = "Access-Control-Allow-Origin" content = "*">
Герберт Амарал

7
@HerberthAmaral Я пытался добавить это внутри <head> </ head>, но у меня это не работает. Я пытаюсь сделать это в iOS Safari и Chrome, но в консоли я получаю нулевое значение origin, что не допускается ошибкой Access-Control-Allow-Origin.
thandasoru

3
Из соображений безопасности он не работает в заголовке html-файла. Это должен быть заголовок. stackoverflow.com/questions/7015782/…
Джастин Бланк

Этого не может быть в HTML. Это должно быть указано программой, которая отправляет HTML-страницу вашему браузеру по сети (так называемый веб-сервер).
Роман Плашил

70

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

cd project
python -m SimpleHTTPServer 8000

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


1
пока круто и работает, когда вы переходите на 0.0.0.0:8000 и пробуете POSTзапросы, которые вы получаете: code 501, message Unsupported method ('POST')для googles.
Пьяммер

«Когда веб-сервер Python (например, cherrypy) говорит, что он работает на 0.0.0.0, это означает, что он прослушивает весь TCP-трафик, который заканчивается на этом компьютере, независимо от имени хоста или IP, который был запрошен». Поэтому, возможно, попробуйте опубликовать на localhost: 8000 stackoverflow.com/a/4341808/102022
eric.christensen

20

У меня работает в 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.


Хм хорошо, позвольте мне попробовать еще раз. Я на другой версии Chrome, кстати, "6.0.472.51 бета".
Дрю Ноакс

Ваш код работал для меня. Я обновил свой вопрос с некоторым кодом, который решает проблему, хотя.
Дрю Ноакс

Спасибо за совет re getJSON ... Я разобрал ваш пример jsFiddle, чтобы показать проблему ( jsfiddle.net/ZfvKm ), и теперь вижу сообщение об ошибке XMLHttpRequest не может загрузить Panoramio.com/wapi/data/… . Происхождение fiddle.jshell.net не разрешено Access-Control-Allow-Origin.
Дрю Ноакс

@ Darin, спасибо за обновление. Я понимаю вашу точку зрения, и я поиграл с несколькими комбинациями этого, но мне еще предстоит найти способ получить доступ к возвращенному объекту. Не могли бы вы обновить пример jsFiddle, чтобы показать доступ к данным? Если вы установите обратный вызов, ?то возвращаемый JSON будет заключен в круглые скобки. Вы не определяете параметр для своей функции обратного вызова, и значение, по- thisвидимому, не имеет объекта ответа (по крайней мере, .dataзначение равно null).
Дрю Ноакс

@ Darin, потрясающе. Большое спасибо. Работает хорошо сейчас. Для всех, кто читает это, включение callback=?jQuery указывает внутреннему генерированию случайного имени функции, что приводит к вызову анонимной функции, которую вы передаете .getJSON. Оценил.
Дрю Ноакс

8

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



4

Нам это удалось через 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. проблема все еще существует.
Raptor

1
Это небезопасно. Смотрите здесь, почему; stackoverflow.com/questions/7564832/…
Роб

Это небезопасно, как сказал @RobQuist.
d337

4

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

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


3

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


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

Я использую сервер 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 в ваш скрипт.


1

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

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

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


1

Для PHP - это работа для меня на Chrome, Safari и Firefox

https://w3c.github.io/webappsec-cors-for-developers/#avoid-returning-access-control-allow-origin-null

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

используя axios вызов php live сервисов с файлом: //


Это также работает от меня, обратите внимание, что null является STRING, а не фактическим NULL. Я использую его как header('Access-Control-Allow-Origin: '.( trim($_SERVER['HTTP_REFERER'],'/') ?:'null'),true);разрешающий перекрестное происхождение с удаленного сервера на другой, а также для (локального) нуля для локального файла.
Луи Лоудог Троттье

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

Folks,

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

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

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

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

Спасибо энди


0

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

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

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

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


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

Уточнил ссылку.
MiJyn
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.