jQuery AJAX lintas domain

477

Berikut adalah dua halaman, test.php dan testserver.php.

test.php

<script src="scripts/jq.js" type="text/javascript"></script>
<script>
    $(function() {
        $.ajax({url:"testserver.php",
            success:function() {
                alert("Success");
            },
            error:function() {
                alert("Error");
            },
            dataType:"json",
            type:"get"
        }
    )})
</script>

testserver.php

<?php
$arr = array("element1",
             "element2",
             array("element31","element32"));
$arr['name'] = "response";
echo json_encode($arr);
?>

Sekarang masalah saya: ketika kedua file ini berada di server yang sama (baik localhost atau server web), ia berfungsi dan alert("Success")dipanggil; Jika ada di server yang berbeda, artinya testserver.php di server web dan test.php di localhost, itu tidak berfungsi, dan alert("Error")sedang dijalankan. Bahkan jika URL di dalam ajax diubah menjadi http://domain.com/path/to/file/testserver.php

Firose Hussain
sumber
38
Untuk orang-orang yang mampir. Baca ini untuk mengetahui bagaimana panggilan lintas domain javascript berfungsi stackoverflow.com/a/11736771/228656
Abdul Munim
1
Saya menulis jawaban untuk pertanyaan ini di sini: Memuat halaman html lintas domain dengan jQuery AJAX - yang terakhir, mendukung https
jherax

Jawaban:

412

Gunakan JSONP .

jQuery:

$.ajax({
     url:"testserver.php",
     dataType: 'jsonp', // Notice! JSONP <-- P (lowercase)
     success:function(json){
         // do stuff with json (in this case an array)
         alert("Success");
     },
     error:function(){
         alert("Error");
     }      
});

PHP:

<?php
$arr = array("element1","element2",array("element31","element32"));
$arr['name'] = "response";
echo $_GET['callback']."(".json_encode($arr).");";
?>

Gema mungkin salah, sudah lama sejak saya menggunakan php. Dalam hal apa pun Anda perlu menampilkan callbackName('jsonString')pemberitahuan harga. jQuery akan memberikan nama panggilan baliknya sendiri, jadi Anda harus mendapatkannya dari parnet GET.

Dan seperti yang diposting oleh Stefan Kendall, $ .getJSON () adalah metode singkat, tetapi kemudian Anda perlu menambahkan 'callback=?'url sebagai parameter GET (ya, nilainya?, JQuery menggantikan ini dengan metode panggilan balik yang dihasilkan sendiri).

BGerrissen
sumber
2
Mengapa Anda harus kembali, callbackName('/* json */')bukan callbackName(/* json */)?
Eric
3
@ eric panggilan balik mengharapkan string JSON. Secara teoritis, suatu objek mungkin bekerja juga, tetapi tidak yakin bagaimana jQuery merespons ini, ia mungkin melempar kesalahan atau gagal diam-diam.
BGerrissen
Saya mendapatkan kesalahan berikut. SyntaxError: hilang; sebelum pernyataan {"ResultCode": 2}. Di mana {"ResultCode": 2} adalah respons. Tolong saran.
user2003356
@ user2003356 sepertinya Anda mengembalikan JSON biasa, bukan JSONP. Anda perlu mengembalikan sesuatu seperti: callbackFunction ({"ResultCode": 2}). jQuery menambahkan parameter GET 'panggilan balik' ke permintaan, itulah nama fungsi panggilan balik yang digunakan jquery dan harus ditambahkan ke respons.
BGerrissen
2
Ini 2016. CORS sekarang menjadi standar yang didukung secara luas, bukan JSONP yang hanya dapat digambarkan sebagai peretasan. @joshuarh jawaban di bawah ini harus menjadi yang disukai sekarang.
Vicky Chijwani
202

JSONP adalah pilihan yang bagus, tetapi ada cara yang lebih mudah. Anda cukup mengatur Access-Control-Allow-Originheader di server Anda. Menyetelnya untuk *akan menerima permintaan AJAX lintas-domain dari domain apa pun. ( https://developer.mozilla.org/en/http_access_control )

Metode untuk melakukan ini akan bervariasi dari satu bahasa ke bahasa lainnya, tentu saja. Ini dia di Rails:

class HelloController < ApplicationController
  def say_hello
    headers['Access-Control-Allow-Origin'] = "*"
    render text: "hello!"
  end
end

Dalam contoh ini, say_hellotindakan akan menerima permintaan AJAX dari domain apa pun dan mengembalikan respons "halo!".

Berikut adalah contoh header yang mungkin kembali:

HTTP/1.1 200 OK 
Access-Control-Allow-Origin: *
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: text/html; charset=utf-8
X-Ua-Compatible: IE=Edge
Etag: "c4ca4238a0b923820dcc509a6f75849b"
X-Runtime: 0.913606
Content-Length: 6
Server: WEBrick/1.3.1 (Ruby/1.9.2/2011-07-09)
Date: Thu, 01 Mar 2012 20:44:28 GMT
Connection: Keep-Alive

Semudah itu, memang ada beberapa batasan browser. Lihat http://caniuse.com/#feat=cors .

joshuarh
sumber
12
Jsonp tidak mendukung posting, menaruh, dan menghapus. Solusi Anda sangat bagus.
TonyTakeshi
35
di header PHP ("Access-Control-Allow-Origin: *");
SparK
9
@ Prajurit Jika Anda menggunakan .post()metode jQuery, Anda harus mengaktifkan dukungan lintas domain di jQuery. Hal ini dilakukan dengan ini: $.support.cors = true.
Friederike
21
Apa implikasi keamanan konfigurasi server dengan cara ini?
Jon Schneider
19
Akan lebih baik jika hanya mengizinkan domain yang ingin Anda bagikan data daripada menggunakan wilcard "*".
Sebastián Grignoli
32

Anda dapat mengontrol ini melalui tajuk HTTP dengan menambahkan Access-Control-Allow-Origin . Menetapkannya ke * akan menerima permintaan AJAX lintas-domain dari domain apa pun.

Menggunakan PHP sangat sederhana, cukup tambahkan baris berikut ke dalam skrip yang ingin Anda akses di luar dari domain Anda:

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

Jangan lupa untuk mengaktifkan modul mod_headers di httpd.conf.

Adorjan Princz
sumber
kamu menyelamatkan hariku.
NomanJaved
20

Anda perlu melihat Kebijakan Same Origin :

Dalam komputasi, kebijakan asal yang sama adalah konsep keamanan penting untuk sejumlah bahasa pemrograman sisi browser, seperti JavaScript. Kebijakan ini memungkinkan skrip berjalan pada halaman yang berasal dari situs yang sama untuk mengakses metode dan properti masing-masing tanpa batasan spesifik, tetapi mencegah akses ke sebagian besar metode dan properti di seluruh halaman di situs yang berbeda.

Agar Anda bisa mendapatkan data, itu harus:

Protokol dan host yang sama

Anda perlu menerapkan JSONP untuk mengatasinya.

Sarfraz
sumber
17

Saya harus memuat halaman web dari disk "file: /// C: /test/htmlpage.html", panggil "http: //localhost/getxml.php" url, dan lakukan ini di browser IE8 + dan Firefox12 +, gunakan jQuery v1 .7.2 lib untuk meminimalkan kode boilerplate. Setelah membaca lusinan artikel akhirnya menemukan jawabannya. Ini ringkasan saya.

  • skrip server (.php, .jsp, ...) harus mengembalikan header respons http Access-Control-Allow-Origin: *
  • sebelum menggunakan jQuery ajax atur flag ini dalam javascript: jQuery.support.cors = true;
  • Anda dapat mengatur flag sekali atau setiap kali sebelum menggunakan fungsi jQuery ajax
  • sekarang saya bisa membaca dokumen .xml di IE dan Firefox. Peramban lain yang tidak saya uji.
  • dokumen respons dapat berupa teks / polos, xml, json atau apa pun

Berikut adalah contoh panggilan ajax jQuery dengan beberapa sysouts debug.

jQuery.support.cors = true;
$.ajax({
    url: "http://localhost/getxml.php",
    data: { "id":"doc1", "rows":"100" },
    type: "GET",
    timeout: 30000,
    dataType: "text", // "xml", "json"
    success: function(data) {
        // show text reply as-is (debug)
        alert(data);

        // show xml field values (debug)
        //alert( $(data).find("title").text() );

        // loop JSON array (debug)
        //var str="";
        //$.each(data.items, function(i,item) {
        //  str += item.title + "\n";
        //});
        //alert(str);
    },
    error: function(jqXHR, textStatus, ex) {
        alert(textStatus + "," + ex + "," + jqXHR.responseText);
    }
});
Siapa
sumber
1
Saya menulis jawaban untuk pertanyaan ini di sini: Memuat halaman html lintas domain dengan jQuery AJAX - yang terakhir, mendukung https
jherax
Untuk titik paling terang: di PHP tambahkan baris ini ke skrip:header("Access-Control-Allow-Origin: *");
T30
1
@ siapa terima kasih banyak atas jawaban Anda. Anda banyak membantu saya. Bersulang.
Luis Milanese
10

Memang benar bahwa kebijakan yang sama-asal mencegah JavaScript dari membuat permintaan di seluruh domain, tetapi spesifikasi CORS memungkinkan hanya jenis akses API yang Anda cari, dan didukung oleh kumpulan browser utama saat ini.

Lihat cara mengaktifkan berbagi sumber daya lintas-asal untuk klien dan server:

http://enable-cors.org/

"Cross-Origin Resource Sharing (CORS) adalah spesifikasi yang memungkinkan akses benar-benar terbuka melintasi batas-batas domain. Jika Anda menyajikan konten publik, pertimbangkan untuk menggunakan CORS untuk membukanya untuk akses universal JavaScript / browser."

Jason
sumber
9

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
8

Keamanan browser mencegah melakukan panggilan ajax dari halaman yang dihosting di satu domain ke halaman yang di-host di domain yang berbeda; ini disebut " kebijakan asal-sama ".

Jacob Mattison
sumber
4

Dari dokumen Jquery ( tautan ):

  • Karena pembatasan keamanan browser, sebagian besar permintaan "Ajax" tunduk pada kebijakan asal yang sama; permintaan tidak dapat berhasil mengambil data dari domain, subdomain, atau protokol yang berbeda.

  • Permintaan skrip dan JSONP tidak tunduk pada batasan kebijakan asal yang sama.

Jadi saya anggap Anda perlu menggunakan jsonp untuk permintaan tersebut. Tetapi saya belum mencobanya sendiri.

William Clemens
sumber
2

Saya tahu 3 cara untuk menyelesaikan masalah Anda:

  1. Pertama, jika Anda memiliki akses ke kedua domain, Anda dapat mengizinkan akses untuk semua domain lain menggunakan:

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

    atau hanya domain dengan menambahkan kode di bawah ke file .htaccess:

    <FilesMatch "\.(ttf|otf|eot|woff)$"> <IfModule mod_headers.c> SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.net|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0 Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin </IfModule> </FilesMatch>

  2. Anda dapat memiliki permintaan ajax ke file php di server Anda dan menangani permintaan ke domain lain menggunakan file php ini.

  3. Anda dapat menggunakan jsonp, karena tidak memerlukan izin. untuk ini, Anda dapat membaca jawaban teman kami @BGerrissen.
Ali_Hr
sumber
0

Untuk Microsoft Azure, ini sedikit berbeda.

Azure memiliki pengaturan CORS khusus yang perlu diatur. Ini pada dasarnya hal yang sama di balik layar, tetapi hanya mengatur header joshuarh menyebutkan tidak akan berfungsi. Dokumentasi Azure untuk mengaktifkan lintas domain dapat ditemukan di sini:

https://docs.microsoft.com/en-us/azure/app-service-api/app-service-api-cors-consume-javascript

Saya bermain-main dengan ini selama beberapa jam sebelum menyadari platform hosting saya memiliki pengaturan khusus ini.

Josh Schultz
sumber
0

itu bekerja, semua yang Anda butuhkan:

PHP:

header('Access-Control-Allow-Origin: http://www.example.com');
header("Access-Control-Allow-Credentials: true");
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');

JS (jQuery ajax):

var getWBody = $.ajax({ cache: false,
        url: URL,
        dataType : 'json',
        type: 'GET',
        xhrFields: { withCredentials: true }
});
Paun Narcis Iulian
sumber