Помилка XmlHttpRequest: Null Origin не дозволено Access-Control-Allow-Origin


550

Я розробляю сторінку, яка витягує зображення з Flickr та Panoramio через підтримку AJAX jQuery.

Сторона 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 . Origin null не дозволяється Access-Control-Allow-Origin.

Якщо я запитую цю URL-адресу у веб-переглядача, вона працює добре. Що відбувається, і чи можу я обійти це? Чи складаю я запит неправильно, чи це щось, що робить Panoramio, щоб перешкоджати тому, що я намагаюся зробити?

Google не виявив корисних збігів у повідомленні про помилку .

EDIT

Ось приклад коду, який показує проблему:

$().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);
  });
});

Ви можете запустити приклад в Інтернеті .

EDIT 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, наприклад,?
Pekka

5
Чи можете ви опублікувати відповідь HTTP із запиту на кожну службу. Б'юсь об заклад, Panoramio не обслуговує Access Control-Allow-Origin. Див. Приклади w3.org/TR/cors .
Кевін Хакансон

2
@Kevin, вам не потрібні ці заголовки, якщо сервер надсилає JSONP.
Дарин Димитров

@Pekka, я зараз запускаю сторінку з моєї локальної машини ( file:///C:/). Ніхто iframeне бере участь.
Дрю Ноакс

1
@drew що станеться, якщо запустити його з http URL? Це не повинно змінювати цей спосіб, а просто виключити можливість.
Pekka

Відповіді:


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який неможливо авторизувати за допомогою ехо-зворотного зв’язку.

Перший був вирішений круговим способом через пропозицію Даріна використовувати $.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
Деякі браузери, як хром, дозволяють CORS, якщо почати з параметра --allow-file-access-from-files
echox

1
callback=?не працював для мене, але так і jsonp=?робив. Будь-яке пояснення цьому?
хрускіт

1
Чи потрібно встановити веб-сервер для тестування через http://? Або є спосіб просто відкрити файл за допомогою цього протоколу?
Буде Сьюелл

76

Вам потрібно, можливо, додати HEADER у названий сценарій, ось що мені довелося зробити в PHP:

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

Детальніше у крос-доменній послузі AJAX ou WEB (французькою мовою).


1
@Uri: Залежить від вашого HTTP-сервера. За допомогою Apache ви захочете заглянути в mod_headers.
ssokolow

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

7
@HerberthAmaral Я спробував додати це всередині <head> </head>, але це не працює для мене. Я пробую це в iOS Safari та Chrome, але в консолі я отримую, що нульове джерело заборонено помилкою 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.
pjammer

"Коли веб-сервер Python (наприклад, cherrypy) каже, що він працює на 0.0.0.0, це означає, що він прослуховує весь трафік TCP, який закінчується на цій машині, незалежно від імені хоста чи IP-адреси, про який запитували." Так що, може бути , спробуйте розмістити на локальний хост: 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. Ось так працює підтримка JQuery JSONP. Зверніть увагу, як я визначаю, callback=?щоб ви могли використовувати анонімну функцію. Детальніше про це ви можете прочитати в документації .

Ще одне зауваження полягає в тому, що не варто називати eval. Параметр, переданий вашій анонімній функції, буде вже проаналізований в JSON jQuery.


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

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

Дякуємо за підказку getJSON ... Я подав ваш приклад jsFiddle, щоб показати проблему ( jsfiddle.net/ZfvKm ), і тепер побачите повідомлення про помилку. XMLHttpRequest не може завантажити panoramio.com/wapi/data/… . Origin 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. проблема все ще існує.
Раптор

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/

Нарешті, передайте проксі-URL до свого сценарію.


1

На завершення документація Mozilla прямо говорить про це

Наведений вище приклад не вдасться, якщо заголовок було позначено як: Access-Control-Allow-Origin: *. Оскільки Access-Control-Allow-Origin прямо згадує http: //foo.example , вміст обліково -пізнавальних даних повертається до веб-вмісту, що викликає посилання.

Як наслідок, це не просто погана практика використовувати "*". Просто не працює :)


1

Для PHP - це робота для мене на Chrome, сафарі та firefox

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

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

використання служб живлення служб axios call php з файлом: //


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

0

Я також отримав таку ж помилку в Chrome (я не тестував інших веб-переглядачів). Це було пов’язано з тим, що я переміщався на domain.com замість www.domain.com. Трохи дивно, але я міг би вирішити проблему, додавши наступні рядки до .htaccess. Він перенаправляє domain.com на www.domain.com і проблема була вирішена. Я ледачий веб-відвідувач, тому майже ніколи не ввожу веб-сайт, але, мабуть, у деяких випадках це потрібно.

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

0

Переконайтеся, що ви використовуєте останню версію JQuery. Ми стикалися з цією помилкою для JQuery 1.10.2, і помилка була усунена після використання JQuery 1.11.1


0

Люди,

Я зіткнувся з подібним питанням. Але за допомогою Фіддлера я зміг дійти до питання. Проблема полягає в тому, що клієнтська URL-адреса, налаштована в реалізації CORS на стороні Web API, не повинна мати кінцевої нахили вперед. Після подання запиту через Google Chrome та перегляду вкладки TextView розділу заголовків Fiddler, у повідомленні про помилку зазначено приблизно так:

* "Вказане походження політики your_client_url: / 'недійсне. Це не може закінчуватися косою косою переднім рядком."

Це справді химерно, тому що він працював без проблем у Internet Explorer, але приводив до головного болю при тестуванні за допомогою Google Chrome.

Я видалив косу рису в коді CORS і перекомпілював веб-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.