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


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).


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 .


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.


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 .


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

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”.



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.




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.


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.

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.


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 }
});
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.