web-dev-qa-db-fra.com

Interdomaine AJAX demande ne fonctionne pas

J'appelle POST sur une API tierce avec laquelle j'ai travaillé via la fonction $ .ajax de jQuery. Cependant, lorsque je passe l'appel, j'obtiens le message d'erreur suivant: XMLHttpRequest cannot load http://the-url.com. The request was redirected to 'http://the-url.com/anotherlocation', which is disallowed for cross-Origin requests that require preflight. 

J'ai vu dans ce message qu'il s'agissait peut-être d'un bogue Webkit, alors je l'ai essayé dans Firefox (je développe sous Chrome) et j'ai obtenu le même résultat. J'ai déjà essayé cela sur Chrome et Firefox et j'ai le même résultat. 

Per this post , j’ai également essayé d’utiliser jsonp en définissant la propriété crossDomain de la fonction $ .ajax sur true et en définissant la valeur dataType sur jsonp. Mais cela a provoqué une erreur de 500 serveur interne.

Lorsque je lance Chrome avec l'option --disable-web-security, je n'ai aucun problème. Cependant, si je lance le navigateur normalement, j'obtiens l'erreur.

Donc, je suppose que cela pourrait en quelque sorte être une question en 2 parties. Que puis-je faire pour faire cette demande interdomaine? Si JSONP est la solution, comment puis-je déterminer si l'API tierce est configurée correctement pour prendre en charge cela?

EDIT: Voici la capture d'écran lorsque je passe l'appel avec la sécurité du navigateur désactivée: https://drive.google.com/file/d/0Bzo7loNBQcmjUjk5YWNWLXM2SVE/edit?usp=sharing

Voici le screenchost lorsque je passe l'appel avec la sécurité du navigateur activée (comme d'habitude): https://drive.google.com/file/d/0Bzo7loNBQcmjam5NQ3BKWUluRE0/edit?usp=sharing

13
Don

La solution que j'ai proposée consistait à utiliser cURL (comme mentionné par @waki), mais une version légèrement modifiée prenant en charge SOAP. Ensuite, au lieu d'appeler AJAX vers l'API tierce (configurée de manière incorrecte), j'appelle vers mon fichier PHP local, qui passe ensuite un appel SOAP à l'API tierce. et renvoie les données dans mon fichier PHP où je peux ensuite les traiter. Cela me permet d'oublier la SCRO et toutes les complexités qui y sont associées. Voici le code (pris et modifié depuis this question, mais sans l’authentification).

$post_data = "Some xml here";
$soapUrl = "http://yoursite.com/soap.asmx"; // asmx URL of WSDL


$headers = array(
    "Content-type: text/xml;charset=\"utf-8\"",
    "Accept: text/xml",
    "Cache-Control: no-cache",
    "Pragma: no-cache",
    "SOAPAction: http://yoursite.com/SOAPAction",
    "Content-length: " . strlen($post_data),
); //SOAPAction: your op URL

$url = $soapUrl;

// PHP cURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); // the SOAP request
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$response = curl_exec($ch);

/* Check for an error when processing the request. */
if(curl_errno($ch) != 0) {
   // TODO handle the error
}

curl_close($ch);

// TODO Parse and process the $response variable (returned as XML)
3
Don

À votre première question,

Que puis-je faire pour faire cette demande interdomaine?

Les en-têtes de requête suivants sont d'abord envoyés au serveur. Sur la base des en-têtes de réponse, le UserAgent, c'est-à-dire le navigateur ici, ignorera la réponse (le cas échéant) et ne la retournera pas au rappel XHR lorsque les en-têtes ne s'additionnent pas.

Origin: http://yourdomain.com Access-Control-Request-Method: POST Access-Control-Request-Headers: X-Custom-Header

Votre serveur devrait alors répondre avec les en-têtes suivants:

Access-Control-Allow-Origin: http://yourdomain.com Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Headers: X-Custom-Header

Exemple tiré de - https://stackoverflow.com/a/8689332/1304559

Vous pouvez utiliser des outils tels que l'onglet Réseau de Fiddler ou Web Inspector (Chrome) ou l'onglet Réseau de Firebug pour rechercher les en-têtes que le serveur renvoie en réponse à votre demande.

L'URL du serveur d'API tiers doit répondre avec les valeurs prises en charge. Si ce n'est pas le cas, c'est votre problème.

Ne peut pas être d'une grande aide en cas d'erreur du serveur JsonP 500, car il indique Erreur interne du serveur


METTRE À JOUR

J'ai vu vos captures d'écran, quelques choses à noter ici

  1. HTTP POST est utilisé
  2. Aucun en-tête Access-Control trouvé dans la réponse des deux modes. Avec le deuxième code de statut en tant que 302
  3. L'entête de la requête Origin est null. Je pense donc que le fichier HTML est ouvert à partir du système de fichiers plutôt que d'un site Web.

Activer JSONP

Pourquoi JSONP ne fonctionne-t-il pas? La configuration du service Web (spécifiée par ASMX) n'a pas activé le mode GET pour la demande. JSONP ne fonctionne pas avec POST.

Pourquoi 200 avec la sécurité désactivée?

La demande POST est directement appelée, sans aucune variable OPTIONS ni commande de contrôle en amont, de sorte que le serveur répond simplement en retour. 

Pourquoi 302 code d'état avec sécurité activée?

Commençons par expliquer comment cela se produit lorsque l’indicateur de sécurité n’est pas désactivé (par défaut). La demande OPTIONS est renvoyée à l'URL. L’URL doit répondre avec une liste de méthodes HTTP pouvant être utilisées, à savoir GET, POST, etc. Le code d’état de cette demande OPTIONS doit être 200

Dans le cas présent, une redirection est appelée lors de cette opération. Et la redirection pointe vers un gestionnaire d’erreurs personnalisé pour une erreur de serveur HTTP. Je crois qu'il s'agit d'une erreur 404 qui est interceptée et redirigée. [Cela pourrait être dû au fait que le gestionnaire personnalisé est défini sur ResponseRedirect au lieu de ResponseRewrite] La raison de 404 est l'accès inter-domaine n'est pas activé.

Si le traitement personnalisé des erreurs était désactivé, le code HTTP 500 aurait été renvoyé. Je pense que le problème peut être résolu en consultant les journaux du serveur immédiatement après le lancement d'une requête inter-domaines. Il sera bon de rechercher dans les journaux du serveur des erreurs autres que celle-ci, le cas échéant.

Solution possible

Pour permettre l'accès, il existe deux manières - détaillées ici . Ou ajoutez directement les en-têtes de contrôle d'accès à la section customheaders du fichier web.config.

Lorsque l'accès entre domaines est activé, le serveur doit répondre à OPTIONS et autoriser le traitement de la demande. Cela devrait renvoyer HTTP 200 à moins qu'il y ait d'autres erreurs. Mais le rappel ajax ne pourra pas accéder à la réponse. Cela ne peut être fait maintenant que si Access-Control-Allow-Origin est défini sur "*" ou la valeur de l'en-tête de la requête Origin, et le Access-Control si nécessaire. Et le rappel ajax recevra la réponse comme prévu.

Le troisième point, null Origin. Cela posera un problème si la valeur de l'en-tête de la requête Origin est renvoyée sous la forme Access-Control-Allow-Origin. Mais je suppose que vous déplacerez votre page HTML sur un serveur Web. Cela ne devrait donc pas poser de problème.

J'espère que cela t'aides!

20
aravind

Vous pouvez utiliser cURL? Avec Ajax vous envoyez des données à votre gestionnaire (sur votre serveur, appelez callback.php) . Dans votre fichier (callback.php), utilisez cURL avec vos données:

$post_data = array( 
    'key' => 'key', 
    'test' => 'text'
    ); 

$curl = curl_init(); 
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); 
curl_setopt($curl, CURLOPT_POST, TRUE); 
curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);  
curl_setopt($curl, CURLOPT_URL, 'http://www.domain.com/'); 
$return = json_decode(trim(curl_exec($curl)), TRUE); 
curl_close($curl); 

dans votre variable $ return, vous obtenez vos données.

1
waki