jQuery AJAX między domenami

477

Oto dwie strony: test.php i 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);
?>

Teraz mój problem: gdy oba te pliki znajdują się na tym samym serwerze (localhost lub web server), działa i alert("Success")jest wywoływany; Jeśli znajduje się na różnych serwerach, co oznacza testserver.php na serwerze WWW i test.php na localhost, to nie działa i alert("Error")działa. Nawet jeśli adres URL wewnątrz ajax zostanie zmieniony na http://domain.com/path/to/file/testserver.php

Firose Hussain
źródło
38
Dla ludzi zatrzymujących się w pobliżu. Przeczytaj to, aby dowiedzieć się, jak działają wywołania javascript między domenami stackoverflow.com/a/11736771/228656
Abdul Munim
1
Odpowiedziałem na to pytanie tutaj: Ładowanie strony HTML między domenami z jQuery AJAX - ostatnia, obsługuje https
jherax

Odpowiedzi:

412

Użyj 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).");";
?>

Echo może się mylić, minęło trochę czasu odkąd użyłem php. W każdym przypadku musisz callbackName('jsonString')podać notowania. jQuery przekaże własną nazwę wywołania zwrotnego, więc musisz ją pobrać z parametrów GET.

I jak napisał Stefan Kendall, $ .getJSON () jest metodą skróconą, ale następnie musisz dołączyć do adresu 'callback=?'URL jako parametr GET (tak, wartość wynosi?, JQuery zamienia to na własną wygenerowaną metodę wywołania zwrotnego).

BGerrissen
źródło
2
Dlaczego musisz wrócić callbackName('/* json */')zamiast callbackName(/* json */)?
Eric,
3
@eric wywołanie zwrotne oczekuje ciągu JSON. Teoretycznie obiekt może również działać, ale nie jest pewne, w jaki sposób jQuery na to zareaguje, może zgłosić błąd lub po cichu zawieść.
BGerrissen
Otrzymuję następujący błąd. Błąd składni: brak; przed instrukcją {„ResultCode”: 2}. Gdzie {„ResultCode”: 2} jest odpowiedzią. Proszę o poradę.
user2003356
@ user2003356 wygląda na to, że zwracasz zwykły JSON zamiast JSONP. Musisz zwrócić coś takiego: callbackFunction ({„ResultCode”: 2}). jQuery dodaje do żądania parametr GET „callback”, jest to nazwa funkcji zwrotnej, której używa jquery, i należy ją dodać do odpowiedzi.
BGerrissen
2
Jest 2016. CORS jest obecnie szeroko wspieranym standardem, w przeciwieństwie do JSONP, który można określić tylko jako hack. Odpowiedź @ joshuarh poniżej powinna być teraz preferowana.
Vicky Chijwani,
202

JSONP to dobra opcja, ale istnieje prostszy sposób. Możesz po prostu ustawić Access-Control-Allow-Originnagłówek na swoim serwerze. Ustawienie go na *akceptowanie żądań AJAX między domenami z dowolnej domeny. ( https://developer.mozilla.org/en/http_access_control )

Oczywiście sposób na zrobienie tego będzie różny w zależności od języka. Oto w Railsach:

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

W tym przykładzie say_helloakcja zaakceptuje żądania AJAX z dowolnej domeny i zwróci odpowiedź „cześć!”.

Oto przykład nagłówków, które może zwrócić:

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

Choć jest to proste, ma pewne ograniczenia przeglądarki. Zobacz http://caniuse.com/#feat=cors .

joshuarh
źródło
12
Jsonp nie obsługiwał wysyłania, umieszczania i usuwania. Twoje rozwiązanie działa świetnie.
TonyTakeshi,
35
w nagłówku PHP („Access-Control-Allow-Origin: *”);
SparK
9
@Warrior Jeśli używasz metody jQuery, .post()musisz włączyć obsługę wielu domen w jQuery. Odbywa się to z tym: $.support.cors = true.
Friederike
21
Jakie są konsekwencje bezpieczeństwa związane z konfigurowaniem serwera w ten sposób?
Jon Schneider
19
Lepiej byłoby zezwolić tylko tym domenom, którym chcesz udostępnić dane, zamiast używać wilcard „*”.
Sebastián Grignoli,
32

Możesz to kontrolować za pomocą nagłówka HTTP, dodając Access-Control-Allow-Origin . Ustawienie na * akceptuje żądania AJAX między domenami z dowolnej domeny.

Korzystanie z PHP jest naprawdę proste, wystarczy dodać następujący wiersz do skryptu, do którego chcesz mieć dostęp poza domeną:

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

Nie zapomnij włączyć modułu mod_headers w httpd.conf.

Adorjan Princz
źródło
uratowałeś mi dzień
NomanJaved
20

Musisz zapoznać się z Polityką tego samego pochodzenia :

W informatyce ta sama zasada pochodzenia jest ważną koncepcją bezpieczeństwa dla wielu języków programowania po stronie przeglądarki, takich jak JavaScript. Zasady zezwalają skryptom działającym na stronach pochodzących z tej samej witryny na wzajemny dostęp do metod i właściwości bez szczególnych ograniczeń, ale uniemożliwiają dostęp do większości metod i właściwości między stronami w różnych witrynach.

Abyś mógł uzyskać dane, musi to być:

Ten sam protokół i host

Aby obejść ten problem, musisz zaimplementować JSONP .

Sarfraz
źródło
17

Musiałem załadować stronę z lokalnego dysku „plik: /// C: /test/htmlpage.html”, wywołać „http: //localhost/getxml.php” URL i zrobić to w przeglądarkach IE8 + i Firefox12 +, użyć jQuery v1 .7.2 lib w celu zminimalizowania kodu szablonu. Po przeczytaniu dziesiątek artykułów w końcu się zorientowałem. Oto moje streszczenie.

  • skrypt serwera (.php, .jsp, ...) musi zwracać nagłówek odpowiedzi http Access-Control-Allow-Origin: *
  • przed użyciem jQuery ajax ustaw tę flagę w javascript: jQuery.support.cors = true;
  • możesz ustawić flagę raz lub za każdym razem przed użyciem funkcji ajax jQuery
  • teraz mogę odczytać dokument .xml w IE i Firefox. Inne przeglądarki, których nie testowałem.
  • dokument odpowiedzi może być zwykły / tekstowy, xml, json lub cokolwiek innego

Oto przykładowe wywołanie jQuery ajax z niektórymi sysoutami debugującymi.

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);
    }
});
Kto ja
źródło
1
Odpowiedziałem na to pytanie tutaj: Ładowanie strony HTML między domenami z jQuery AJAX - ostatnia, obsługuje https
jherax
Dla punktu ogniowego: w PHP dodaj ten wiersz do skryptu:header("Access-Control-Allow-Origin: *");
T30
1
@ komu dziękuję BARDZO za odpowiedź. Bardzo mi pomogłeś. Twoje zdrowie.
Luis Milanese,
10

Prawdą jest, że zasada tego samego pochodzenia uniemożliwia JavaScript wysyłanie żądań między domenami, ale specyfikacja CORS pozwala tylko na rodzaj dostępu API, którego szukasz, i jest obsługiwana przez bieżącą partię głównych przeglądarek.

Zobacz, jak włączyć współużytkowanie zasobów między źródłami dla klienta i serwera:

http://enable-cors.org/

„Udostępnianie zasobów między różnymi źródłami (CORS) to specyfikacja, która umożliwia naprawdę otwarty dostęp ponad granicami domen. Jeśli udostępniasz treści publiczne, rozważ użycie CORS do otwarcia na uniwersalny dostęp do JavaScript / przeglądarki”.

Jason
źródło
9

Używam serwera Apache, więc użyłem modułu mod_proxy. Włącz moduły:

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

Następnie dodaj:

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

Na koniec przekaż adres URL proxy do skryptu.

zenio
źródło
8

Zabezpieczenia przeglądarki zapobiegają nawiązywaniu połączenia ajax ze strony hostowanej w jednej domenie do strony hostowanej w innej domenie; nazywa się to „ polityką tego samego pochodzenia ”.

Jacob Mattison
źródło
4

Z dokumentacji Jquery ( link ):

  • Z powodu ograniczeń bezpieczeństwa przeglądarki większość żądań „Ajax” podlega tym samym zasadom pochodzenia; żądanie nie może pomyślnie pobrać danych z innej domeny, subdomeny lub protokołu.

  • Żądania skryptów i JSONP nie podlegają tym samym ograniczeniom zasad pochodzenia.

Przyjmę więc, że musisz użyć jsonp do żądania. Ale sam tego nie próbowałem.

William Clemens
źródło
2

Znam 3 sposoby rozwiązania twojego problemu:

  1. Po pierwsze, jeśli masz dostęp do obu domen, możesz zezwolić na dostęp do wszystkich innych domen, używając:

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

    lub po prostu domenę, dodając poniższy kod do pliku .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. możesz mieć żądanie ajax do pliku php na serwerze i obsługiwać żądanie do innej domeny za pomocą tego pliku php.

  3. możesz użyć jsonp, ponieważ nie wymaga on pozwolenia. za to możesz przeczytać odpowiedź naszego znajomego @BGerrissen.
Ali_Hr
źródło
0

W przypadku Microsoft Azure jest nieco inny.

Azure ma specjalne ustawienie CORS, które należy ustawić. Jest to zasadniczo to samo za kulisami, ale po prostu ustawienie nagłówka, o którym wspomina joshuarh, nie będzie działać. Dokumentację platformy Azure dotyczącą włączania wielu domen można znaleźć tutaj:

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

Przez kilka godzin bawiłem się tym, zanim zdałem sobie sprawę, że moja platforma hostingowa ma takie specjalne ustawienie.

Josh Schultz
źródło
0

to działa, wszystko czego potrzebujesz:

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
źródło