Kesalahan XmlHttpRequest: Origin null tidak diizinkan oleh Access-Control-Allow-Origin

550

Saya sedang mengembangkan halaman yang menarik gambar dari Flickr dan Panoramio melalui dukungan AJAX jQuery.

Sisi Flickr berfungsi dengan baik, tetapi ketika saya mencoba $.get(url, callback)dari Panoramio, saya melihat kesalahan di konsol Chrome:

XMLHttpRequest tidak dapat memuat 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 . Asal nol tidak diizinkan oleh Access-Control-Allow-Origin.

Jika saya menanyakan URL itu dari browser secara langsung, URL itu berfungsi dengan baik. Apa yang terjadi, dan bisakah saya menyiasati ini? Apakah saya salah menyusun kueri, atau apakah ini sesuatu yang dilakukan Panoramio untuk menghalangi apa yang saya coba lakukan?

Google tidak menemukan kecocokan yang bermanfaat pada pesan kesalahan .

EDIT

Berikut beberapa contoh kode yang menunjukkan masalah:

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

Anda dapat menjalankan contoh secara online .

EDIT 2

Terima kasih kepada Darin untuk bantuannya dengan ini. KODE DI ATAS SALAH. Gunakan ini sebagai gantinya:

$().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...
  });
});
Drew Noakes
sumber
1
Apa URL terlihat seperti bahwa Anda membuat permintaan dari ? Sebagai contoh, ini tidak menghasilkan iframeAnda secara dinamis document.write?
Pekka
5
Dapatkah Anda mengirim respons HTTP dari permintaan ke setiap layanan. Saya yakin Panoramio tidak melayani Access-Control-Allow-Origin. Lihat w3.org/TR/cors untuk contoh.
Kevin Hakanson
2
@ Kevin, Anda tidak perlu header itu jika server mengirim JSONP.
Darin Dimitrov
@ Pekka, saya sedang menjalankan halaman dari mesin lokal saya saat ini ( file:///C:/). Tidak ada iframeyang terlibat.
Drew Noakes
1
@drew apa yang terjadi jika Anda menjalankannya dari URL http? Seharusnya tidak membuat perbedaan seperti ini, tetapi hanya untuk mengecualikan kemungkinan.
Pekka

Jawaban:

423

Sebagai catatan, sejauh yang saya tahu, Anda memiliki dua masalah:

  1. Anda tidak meneruskan specifier tipe "jsonp" ke Anda $.get, jadi itu menggunakan XMLHttpRequest biasa. Namun, browser Anda mendukung CORS (Cross-Origin Resource Sharing) untuk memungkinkan cross-domain XMLHttpRequest jika server menyetujuinya. Di situlah Access-Control-Allow-Originsundulan masuk.

  2. Saya yakin Anda menyebutkan bahwa Anda menjalankannya dari file: // URL. Ada dua cara untuk header CORS untuk memberi sinyal bahwa XHR lintas-domain adalah OK. Yang pertama adalah mengirim Access-Control-Allow-Origin: *(yang, jika Anda menghubungi Flickr melalui $.get, mereka pasti telah melakukan) sementara yang lain adalah untuk mengulang kembali isi Originheader. Namun, file://URL menghasilkan nol Originyang tidak dapat diotorisasi melalui echo-back.

Yang pertama diselesaikan secara tidak langsung oleh saran Darwin untuk digunakan $.getJSON. Itu sedikit sihir untuk mengubah jenis permintaan dari default "json" menjadi "jsonp" jika melihat substring callback=?di URL.

Itu memecahkan yang kedua dengan tidak lagi mencoba melakukan permintaan CORS dari file://URL.

Untuk menjelaskan kepada orang lain, berikut adalah petunjuk pemecahan masalah sederhana:

  1. Jika Anda mencoba menggunakan JSONP, pastikan salah satu dari yang berikut adalah masalahnya:
    • Anda menggunakan $.getdan diatur dataTypeke jsonp.
    • Anda menggunakan $.getJSONdan disertakan callback=?dalam URL.
  2. Jika Anda mencoba melakukan cross-domain XMLHttpRequest via CORS ...
    1. Pastikan Anda menguji via http://. Skrip yang berjalan via file://memiliki dukungan terbatas untuk CORS.
    2. Pastikan browser benar-benar mendukung CORS . (Opera dan Internet Explorer terlambat ke pesta)
ssokolow
sumber
45
Jadi apa solusinya?
jQuerybeast
19
panggilan balik =? FTW
Tim
10
Beberapa browser seperti chrome memungkinkan CORS jika mulai dengan parameter --allow-file-access-from-file
echox
1
callback=?tidak bekerja untuk saya, tetapi jsonp=?berhasil. Ada penjelasan untuk itu?
crunkchitis
1
Apakah saya harus menginstal server web untuk diuji http://? Atau adakah cara untuk hanya membuka file menggunakan protokol itu?
Will Sewell
76

Anda mungkin perlu menambahkan HEADER dalam skrip yang Anda panggil, inilah yang harus saya lakukan dalam PHP:

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

Lebih detail dalam Cross domain AJAX atau layanan WEB (dalam bahasa Prancis).

Thomas Decaux
sumber
1
@ Uri: Tergantung pada server HTTP Anda. Dengan Apache, Anda ingin melihat mod_headers.
ssokolow
4
@Uri <meta http-equiv = "Akses-Kontrol-Izinkan-Asal" content = "*">
Herberth Amaral
7
@HerberthAmaral Saya mencoba menambahkan ini di dalam <head> </head>, tetapi tidak berhasil untuk saya. Saya mencobanya di iOS Safari dan Chrome, tetapi di konsol, saya mendapatkan nol asal tidak diizinkan oleh kesalahan Access-Control-Allow-Origin.
thandasoru
3
Itu tidak berfungsi di kepala file html untuk alasan keamanan. Itu harus berupa tajuk. stackoverflow.com/questions/7015782/…
Justin Blank
Itu tidak bisa di HTML. Itu harus ditentukan oleh program yang mengirimkan halaman HTML ke browser Anda melalui jaringan (disebut server web).
Roman Plášil
70

Untuk proyek HTML sederhana:

cd project
python -m SimpleHTTPServer 8000

Kemudian telusuri file Anda.

CodeGroover
sumber
1
sementara mengagumkan dan berfungsi, saat Anda membuka 0.0.0.0:8000 dan mencoba POSTpermintaan yang Anda dapatkan: code 501, message Unsupported method ('POST')untuk googles.
pjammer
"Ketika server web Python (seperti cherrypy misalnya) mengatakan melayani pada 0.0.0.0 itu berarti mendengarkan semua lalu lintas TCP yang berakhir di mesin itu tidak peduli nama host atau IP yang diminta." Jadi mungkin coba posting ke localhost: 8000 stackoverflow.com/a/4341808/102022
eric.christensen
20

Bekerja untuk saya di Google Chrome v5.0.375.127 (saya mendapat peringatan):

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

Juga saya akan merekomendasikan Anda menggunakan $.getJSON()metode ini sebagai gantinya yang sebelumnya tidak bekerja pada IE8 (setidaknya pada mesin saya):

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

Anda dapat mencobanya online dari sini .


MEMPERBARUI:

Sekarang Anda telah menunjukkan kode Anda, saya dapat melihat masalah dengan itu. Anda memiliki fungsi anonim dan fungsi sebaris tetapi keduanya akan dipanggil processImages. Begitulah cara kerja dukungan JSONP jQuery. Perhatikan bagaimana saya mendefinisikan callback=?sehingga Anda dapat menggunakan fungsi anonim. Anda dapat membaca lebih lanjut tentang itu di dokumentasi .

Komentar lain adalah bahwa Anda tidak harus memanggil eval. Parameter yang diteruskan ke fungsi anonim Anda sudah akan diuraikan ke dalam JSON oleh jQuery.

Darin Dimitrov
sumber
Hmm ok izinkan saya coba lagi. Saya menggunakan versi berbeda dari Chrome btw "6.0.472.51 beta".
Drew Noakes
Kode Anda berfungsi untuk saya. Saya memperbarui pertanyaan saya dengan beberapa kode yang menyelesaikan masalah.
Drew Noakes
Terima kasih atas tipnya, getJSON ... Saya bercabang contoh jsFiddle Anda untuk menunjukkan masalah ( jsfiddle.net/ZfvKm ) dan sekarang melihat pesan kesalahan XMLHttpRequest tidak dapat memuat panoramio.com/wapi/data/… . Origin fiddle.jshell.net tidak diizinkan oleh Access-Control-Allow-Origin.
Drew Noakes
@Darin, terima kasih atas pembaruannya. Saya mengerti maksud Anda, dan saya telah bermain dengan beberapa kombinasi dari ini, tetapi saya belum menemukan cara untuk mengakses objek yang dikembalikan. Bisakah Anda memperbarui contoh jsFiddle Anda untuk menunjukkan mengakses data? Jika Anda mengatur panggilan balik ke ?maka JSON kembali dikelilingi dengan tanda kurung. Anda tidak menentukan parameter untuk fungsi panggilan balik Anda, dan nilai thistampaknya tidak memiliki objek respons (setidaknya, .datanilainya null).
Drew Noakes
@Darin, fantastis. Terimakasih banyak. Bekerja dengan baik sekarang. Untuk orang lain yang membaca ini, penyertaan callback=?memberitahu jQuery untuk menghasilkan nama fungsi acak secara internal, menghasilkan panggilan ke fungsi anonim yang Anda berikan .getJSON. Dihargai
Drew Noakes
8

Selama server yang diminta mendukung format data JSON, gunakan antarmuka JSONP (JSONPantding). Hal ini memungkinkan Anda untuk membuat permintaan domain eksternal tanpa server proxy atau hal-hal header mewah.

Cheng Chen
sumber
5

Ini kebijakan asal yang sama , Anda harus menggunakan antarmuka JSON-P atau proxy yang berjalan di host yang sama.

Quentin
sumber
4

Kami mengelolanya melalui http.conffile (diedit dan kemudian memulai kembali layanan 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>

Di Header set Access-Control-Allow-Origin "*", Anda dapat meletakkan URL yang tepat.

romu31
sumber
1
ini tidak berfungsi pada XAMPP Apache. masalahnya masih ada.
Raptor
1
Ini tidak aman. Lihat di sini mengapa; stackoverflow.com/questions/7564832/…
Rob
Tidak aman seperti yang dikatakan @RobQuist.
D337
4

Jika Anda melakukan pengujian lokal atau memanggil file dari sesuatu seperti file://maka Anda harus menonaktifkan keamanan browser.

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

pengguna2701060
sumber
3

Dalam kasus saya, kode yang sama berfungsi dengan baik di Firefox, tetapi tidak di Google Chrome. Konsol JavaScript Google Chrome mengatakan:

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"

Saya harus membuang bagian www dari URL Ajax agar cocok dengan URL asal dan itu berfungsi dengan baik.

Kalpesh Patel
sumber
2

Tidak semua server mendukung jsonp. Ini membutuhkan server untuk mengatur fungsi panggilan balik dalam hasil itu. Saya menggunakan ini untuk mendapatkan tanggapan json dari situs yang mengembalikan json murni tetapi tidak mendukung 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;
    });
}
mAsT3RpEE
sumber
1

Saya menggunakan server Apache, jadi saya menggunakan modul mod_proxy. Aktifkan modul:

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

Kemudian tambahkan:

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

Terakhir, sampaikan proxy-url ke skrip Anda.

zenio
sumber
1

Sebagai catatan akhir, dokumentasi Mozilla secara eksplisit mengatakan itu

Contoh di atas akan gagal jika header itu wildcarded sebagai: Access-Control-Allow-Origin: *. Karena Access-Control-Allow-Origin secara eksplisit menyebutkan http: //foo.example , konten kredensial-sadar dikembalikan ke konten web yang memohon.

Sebagai konsekuensinya bukan hanya praktik buruk untuk menggunakan '*'. Tidak berhasil :)

pengguna2688838
sumber
1

Untuk PHP - Ini berfungsi untuk saya di Chrome, safari, dan firefox

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

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

menggunakan axios panggilan layanan langsung php dengan file: //

Tyler
sumber
Ini juga berfungsi dari saya, Perhatikan bagaimana null adalah STRING dan bukan NULL yang sebenarnya. Saya menggunakannya karena header('Access-Control-Allow-Origin: '.( trim($_SERVER['HTTP_REFERER'],'/') ?:'null'),true);memungkinkan lintas asal dari server jauh ke yang lain dan jatuh ke (string) null untuk file lokal.
Louis Loudog Trottier
0

Saya juga mendapat kesalahan yang sama di Chrome (saya tidak menguji browser lain). Itu karena fakta bahwa saya menavigasi di domain.com bukan www.domain.com. Agak aneh, tapi saya bisa menyelesaikan masalah dengan menambahkan baris berikut ke .htaccess. Ini mengalihkan domain.com ke www.domain.com dan masalahnya selesai. Saya seorang pengunjung web yang malas jadi saya hampir tidak pernah mengetik www tetapi tampaknya dalam beberapa kasus diperlukan.

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

Pastikan Anda menggunakan JQuery versi terbaru. Kami menghadapi kesalahan ini untuk JQuery 1.10.2 dan kesalahan diselesaikan setelah menggunakan JQuery 1.11.1

Ganesh Kamath - 'Code Frenzy'
sumber
0

Orang-orang,

Saya mengalami masalah serupa. Tetapi menggunakan Fiddler, saya bisa mengatasi masalah ini. Masalahnya adalah bahwa URL klien yang dikonfigurasi dalam implementasi CORS di sisi API Web harus tidak memiliki garis miring ke depan. Setelah mengirimkan permintaan Anda melalui Google Chrome dan memeriksa tab TextView dari bagian Header Fiddler, pesan kesalahan menyatakan sesuatu seperti ini:

* "Asal kebijakan yang ditentukan your_client_url: / 'tidak valid. Kebijakan ini tidak dapat diakhiri dengan garis miring."

Ini benar-benar unik karena bekerja tanpa masalah di Internet Explorer, tetapi membuat saya pusing saat pengujian menggunakan Google Chrome.

Saya menghapus garis miring di kode CORS dan mengkompilasi ulang API Web, dan sekarang API dapat diakses melalui Chrome dan Internet Explorer tanpa masalah. Tolong, coba ini.

Terima kasih, Andy

andymenon
sumber
0

Ada masalah kecil dalam solusi yang diposting oleh CodeGroover di atas , di mana jika Anda mengubah file, Anda harus me-restart server untuk benar-benar menggunakan file yang diperbarui (setidaknya, dalam kasus saya).

Jadi mencari sedikit, saya menemukan ini Untuk digunakan:

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

Dan kemudian akan melayani di http://localhost:8000.

MiJyn
sumber
1
Meskipun tautan ini dapat menjawab pertanyaan, lebih baik untuk memasukkan bagian-bagian penting dari jawaban di sini dan memberikan tautan untuk referensi. Jawaban hanya tautan dapat menjadi tidak valid jika halaman tertaut berubah. - Dari Ulasan
Vi100
Klarifikasi tautannya.
MiJyn