jQuery AJAX cross domain

477

Voici deux pages, test.php et 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);
?>

Maintenant mon problème: lorsque ces deux fichiers sont sur le même serveur (localhost ou web server), cela fonctionne et alert("Success")est appelé; S'il se trouve sur des serveurs différents, ce qui signifie testserver.php sur le serveur Web et test.php sur localhost, cela ne fonctionne pas et alert("Error")est en cours d'exécution. Même si l'URL dans ajax est remplacée par http://domain.com/path/to/file/testserver.php

Firose Hussain
la source
38
Pour les gens qui passent. Lisez ceci pour avoir une idée du fonctionnement des appels javascript interdomaines stackoverflow.com/a/11736771/228656
Abdul Munim
1
J'ai écrit une réponse à cette question ici: Chargement d'une page html
interdomaine

Réponses:

412

Utilisez 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).");";
?>

L'écho peut être faux, cela fait un moment que je n'ai pas utilisé php. Dans tous les cas, vous devez afficher callbackName('jsonString')les guillemets. jQuery transmettra son propre nom de rappel, vous devez donc l'obtenir à partir des paramètres GET.

Et comme Stefan Kendall l'a signalé, $ .getJSON () est une méthode abrégée, mais vous devez ensuite ajouter 'callback=?'à l'URL en tant que paramètre GET (oui, la valeur est?, JQuery le remplace par sa propre méthode de rappel générée).

BGerrissen
la source
2
Pourquoi devez-vous revenir callbackName('/* json */')au lieu de callbackName(/* json */)?
Eric
3
@eric le rappel attend une chaîne JSON. Théoriquement, un objet peut également fonctionner, mais vous ne savez pas comment jQuery répond à cela, il peut générer une erreur ou échouer en silence.
BGerrissen
J'obtiens l'erreur suivante. SyntaxError: manquant; avant l'instruction {"ResultCode": 2}. Où {"ResultCode": 2} est la réponse. Veuillez conseiller.
user2003356
@ user2003356 semble renvoyer du JSON ordinaire au lieu de JSONP. Vous devez renvoyer quelque chose comme: callbackFunction ({"ResultCode": 2}). jQuery ajoute le paramètre GET 'callback' à la requête, c'est le nom de la fonction de callback que jquery utilise et doit être ajouté à la réponse.
BGerrissen
2
Nous sommes en 2016. CORS est désormais une norme largement prise en charge, contrairement à JSONP qui ne peut être décrit que comme un hack. La réponse de @ joshuarh ci-dessous devrait être la préférée maintenant.
Vicky Chijwani
202

JSONP est une bonne option, mais il existe un moyen plus simple. Vous pouvez simplement définir l'en- Access-Control-Allow-Origintête sur votre serveur. Le paramétrer sur *acceptera les requêtes AJAX interdomaines de n'importe quel domaine. ( https://developer.mozilla.org/en/http_access_control )

La méthode pour ce faire variera d'une langue à l'autre, bien sûr. Le voici dans Rails:

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

Dans cet exemple, l' say_helloaction acceptera les demandes AJAX de n'importe quel domaine et retournera une réponse "bonjour!".

Voici un exemple des en-têtes qu'il pourrait renvoyer:

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

Aussi simple soit-il, il a quelques limitations de navigateur. Voir http://caniuse.com/#feat=cors .

joshuarh
la source
12
Jsonp n'a pas pris en charge la publication, la mise et la suppression. Votre solution fonctionne très bien.
TonyTakeshi
35
dans l'en-tête PHP ("Access-Control-Allow-Origin: *");
SparK
9
@Warrior Si vous utilisez la .post()méthode de jQuery, vous devez activer la prise en charge inter-domaines dans jQuery. Il est fait avec ceci: $.support.cors = true.
Friederike
21
Quelles sont les implications en termes de sécurité de la configuration d'un serveur de cette manière?
Jon Schneider
19
Il serait préférable de n'autoriser que les domaines avec lesquels vous souhaitez partager les données au lieu d'utiliser la carte wilcard "*".
Sebastián Grignoli
32

Vous pouvez contrôler cela via l'en-tête HTTP en ajoutant Access-Control-Allow-Origin . Le paramétrer sur * acceptera les requêtes AJAX inter-domaines de n'importe quel domaine.

En utilisant PHP, c'est vraiment simple, il suffit d'ajouter la ligne suivante dans le script auquel vous souhaitez avoir accès en dehors de votre domaine:

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

N'oubliez pas d'activer le module mod_headers dans httpd.conf.

Adorjan Princz
la source
tu m'as sauvé la journée.
NomanJaved
20

Vous devez consulter la politique de la même origine :

En informatique, la même politique d'origine est un concept de sécurité important pour un certain nombre de langages de programmation côté navigateur, tels que JavaScript. La stratégie autorise les scripts s'exécutant sur des pages provenant du même site à accéder aux méthodes et propriétés des autres sans restrictions spécifiques, mais empêche l'accès à la plupart des méthodes et propriétés sur les pages de différents sites.

Pour que vous puissiez obtenir des données, il faut:

Même protocole et hôte

Vous devez implémenter JSONP pour le contourner.

Sarfraz
la source
17

J'ai dû charger la page Web à partir du disque local "file: /// C: /test/htmlpage.html", appeler l'URL "http: //localhost/getxml.php" et le faire dans les navigateurs IE8 + et Firefox12 +, utiliser jQuery v1 .7.2 lib pour minimiser le code passe-partout. Après avoir lu des dizaines d'articles, il a finalement compris. Voici mon résumé.

  • le script du serveur (.php, .jsp, ...) doit renvoyer l'en-tête de réponse http Access-Control-Allow-Origin: *
  • avant d'utiliser jQuery ajax, définissez cet indicateur dans javascript: jQuery.support.cors = true;
  • vous pouvez définir l'indicateur une fois ou chaque fois avant d'utiliser la fonction jQuery ajax
  • maintenant je peux lire le document .xml dans IE et Firefox. Autres navigateurs que je n'ai pas testés.
  • le document de réponse peut être en clair / texte, xml, json ou toute autre chose

Voici un exemple d'appel ajQuery jQuery avec quelques sysouts de débogage.

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);
    }
});
Qui
la source
1
J'ai écrit une réponse à cette question ici: Chargement de la page html
interdomaine
Pour le premier point: en PHP ajoutez cette ligne au script:header("Access-Control-Allow-Origin: *");
T30
1
@whome merci beaucoup pour votre réponse. Tu m'as beaucoup aidé. À votre santé.
Luis Milanese
10

Il est vrai que la politique de même origine empêche JavaScript de faire des demandes sur plusieurs domaines, mais la spécification CORS autorise uniquement le type d'accès API que vous recherchez et est prise en charge par le lot actuel des principaux navigateurs.

Découvrez comment activer le partage de ressources d'origine croisée pour le client et le serveur:

http://enable-cors.org/

"Le partage des ressources d'origine croisée (CORS) est une spécification qui permet un accès vraiment ouvert au-delà des limites du domaine. Si vous diffusez du contenu public, veuillez envisager d'utiliser CORS pour l'ouvrir pour un accès universel à JavaScript / navigateur."

Jason
la source
9

J'utilise le serveur Apache, j'ai donc utilisé le module mod_proxy. Activer les modules:

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

Puis ajouter:

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

Enfin, passez proxy-url à votre script.

Zenio
la source
8

La sécurité du navigateur empêche de passer un appel ajax depuis une page hébergée sur un domaine vers une page hébergée sur un domaine différent; c'est ce qu'on appelle la " politique de même origine ".

Jacob Mattison
la source
4

Depuis les documents Jquery ( lien ):

  • En raison des restrictions de sécurité du navigateur, la plupart des demandes "Ajax" sont soumises à la même politique d'origine; la demande ne peut pas récupérer avec succès les données d'un domaine, sous-domaine ou protocole différent.

  • Les requêtes de script et JSONP ne sont pas soumises aux mêmes restrictions de politique d'origine.

Je suppose donc que vous devez utiliser jsonp pour la demande. Mais je n'ai pas essayé ça moi-même.

William Clemens
la source
2

Je connais 3 façons de résoudre votre problème:

  1. Tout d'abord, si vous avez accès aux deux domaines, vous pouvez autoriser l'accès à tous les autres domaines en utilisant:

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

    ou juste un domaine en ajoutant du code ci-dessous au fichier .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. vous pouvez avoir une demande ajax vers un fichier php sur votre serveur et gérer la demande vers un autre domaine en utilisant ce fichier php.

  3. vous pouvez utiliser jsonp, car il n'a pas besoin d'autorisation. pour cela, vous pouvez lire la réponse de notre ami @BGerrissen.
Ali_Hr
la source
0

Pour Microsoft Azure, c'est légèrement différent.

Azure a un paramètre CORS spécial qui doit être défini. C'est essentiellement la même chose dans les coulisses, mais simplement définir l'en-tête que mentionne joshuarh ne fonctionnera pas. La documentation Azure pour l'activation de plusieurs domaines peut être trouvée ici:

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

J'ai bidouillé avec cela pendant quelques heures avant de réaliser que ma plate-forme d'hébergement avait ce paramètre spécial.

Josh Schultz
la source
0

ça marche, tout ce dont vous avez besoin:

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
la source