Comment envoyer une demande interdomaine POST via JavaScript?
Notes - il ne faut pas rafraîchir la page et je dois ensuite récupérer et analyser la réponse.
Mise à jour: Avant de continuer, tout le monde devrait lire et comprendre le didacticiel html5rocks on CORS. C'est facile à comprendre et très clair.
Si vous contrôlez le serveur soumis au POST, utilisez simplement la "norme de partage de ressources d'origine croisée" en définissant des en-têtes de réponse sur le serveur. Cette réponse est discutée dans d'autres réponses dans ce fil de discussion, mais pas très clairement à mon avis.
En bref, voici comment vous accomplissez le domaine croisé POST de from.com/1.html à to.com/postHere.php (en utilisant PHP comme exemple). Remarque: vous devez uniquement définir Access-Control-Allow-Origin
pour les demandes NON OPTIONS
. Cet exemple définit toujours tous les en-têtes pour un extrait de code plus petit.
Dans postHere.php, configurez ce qui suit:
switch ($_SERVER['HTTP_Origin']) {
case 'http://from.com': case 'https://from.com':
header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_Origin']);
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
break;
}
Cela permet à votre script de créer des POST, GET et OPTIONS entre domaines. Cela deviendra clair à mesure que vous continuerez à lire ...
Configurez votre domaine croisé POST à partir de JS (exemple jQuery):
$.ajax({
type: 'POST',
url: 'https://to.com/postHere.php',
crossDomain: true,
data: '{"some":"json"}',
dataType: 'json',
success: function(responseData, textStatus, jqXHR) {
var value = responseData.someKey;
},
error: function (responseData, textStatus, errorThrown) {
alert('POST failed.');
}
});
Lorsque vous effectuez l'opération POST à l'étape 2, votre navigateur envoie une méthode "OPTIONS" au serveur. Ceci est un "reniflement" par le navigateur pour voir si le serveur est cool avec votre POST. Le serveur répond par un message "Access-Control-Allow-Origin" indiquant au navigateur son consentement à POST | GET | Origin si la requête provient de " http://from.com " ou " https: // from.com ". Puisque le serveur est OK avec, le navigateur fera une deuxième demande (cette fois un POST). Il est judicieux de demander à votre client de définir le type de contenu qu'il envoie - vous devez donc également l'autoriser.
MDN a une excellente description de Contrôle de l'accès HTTP , qui décrit en détail le fonctionnement de l'ensemble du flux. Selon leur documentation, il devrait "fonctionner dans les navigateurs prenant en charge XMLHttpRequest sur plusieurs sites". Ceci est toutefois un peu trompeur, car je THINK seuls les navigateurs modernes autorisent le POST entre domaines. J'ai seulement vérifié que cela fonctionne avec Safari, Chrome, FF 3.6.
Gardez à l’esprit ce qui suit si vous procédez ainsi:
Si vous contrôlez le serveur distant, vous devriez probablement utiliser CORS, comme décrit dans cette réponse ; Il est pris en charge dans IE8 et versions ultérieures, ainsi que dans toutes les versions récentes de FF, GC et Safari. (Mais dans IE8 et 9, CORS ne vous autorisera pas à envoyer des cookies dans la requête.)
Ainsi, si vous ne contrôlez pas le serveur distant, ou si vous devez prendre en charge IE7, ou si vous avez besoin de cookies et que vous devez prendre en charge IE8/9, vous voudrez probablement utiliser une technique iframe.
Voici un exemple de code. Je l'ai testé sur IE6, IE7, IE8, IE9, FF4, GC11, S5.
function crossDomainPost() {
// Add the iframe with a unique name
var iframe = document.createElement("iframe");
var uniqueString = "CHANGE_THIS_TO_SOME_UNIQUE_STRING";
document.body.appendChild(iframe);
iframe.style.display = "none";
iframe.contentWindow.name = uniqueString;
// construct a form with hidden inputs, targeting the iframe
var form = document.createElement("form");
form.target = uniqueString;
form.action = "http://INSERT_YOUR_URL_HERE";
form.method = "POST";
// repeat for each parameter
var input = document.createElement("input");
input.type = "hidden";
input.name = "INSERT_YOUR_PARAMETER_NAME_HERE";
input.value = "INSERT_YOUR_PARAMETER_VALUE_HERE";
form.appendChild(input);
document.body.appendChild(form);
form.submit();
}
Il faut se méfier! Vous ne pourrez pas lire directement la réponse du POST, car l'iframe existe sur un domaine séparé. Les cadres ne sont pas autorisés à communiquer entre eux à partir de différents domaines; c'est la politique même origine .
Si vous contrôlez le serveur distant mais que vous ne pouvez pas utiliser CORS (par exemple parce que vous êtes sur IE8/IE9 et que vous devez utiliser des cookies), il existe des moyens de contourner la stratégie de même origine, par exemple en utilisant window.postMessage
et/ou l'une des nombreuses bibliothèques vous permettant d'envoyer des messages inter-domaines entre images dans des navigateurs plus anciens:
Si vous ne contrôlez pas le serveur distant, vous ne pouvez pas lire la réponse du POST, point à la ligne. Sinon, cela causerait des problèmes de sécurité.
Pseudocode
var ifr = document.createElement('iframe');
var frm = document.createElement('form');
frm.setAttribute("action", "yoururl");
frm.setAttribute("method", "post");
// create hidden inputs, add them
// not shown, but similar (create, setAttribute, appendChild)
ifr.appendChild(frm);
document.body.appendChild(ifr);
frm.submit();
Vous voudrez probablement dénommer l'iframe, être caché et positionné de manière absolue. Je ne suis pas sûr que le navigateur permette l'affichage sur plusieurs sites, mais si c'est le cas, voici comment procéder.
Rester simple:
POST interdomaine:
utiliser crossDomain: true,
ne devrait pas rafraîchir la page:
Non, la page n'est pas actualisée car le rappel async success
ou error
est appelé lorsque le serveur renvoie la réponse.
$.ajax({
type: "POST",
url: "http://www.yoururl.com/",
crossDomain: true,
data: 'param1=value1¶m2=value2',
success: function (data) {
// do something with server response data
},
error: function (err) {
// handle your error logic here
}
});
Si vous avez accès à tous les serveurs impliqués, indiquez ce qui suit dans l'en-tête de la réponse pour la page demandée dans l'autre domaine:
PHP:
header('Access-Control-Allow-Origin: *');
Par exemple, dans le code xmlrpc.php de Drupal, vous feriez ceci:
function xmlrpc_server_output($xml) {
$xml = '<?xml version="1.0"?>'."\n". $xml;
header('Connection: close');
header('Content-Length: '. strlen($xml));
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/x-www-form-urlencoded');
header('Date: '. date('r'));
// $xml = str_replace("\n", " ", $xml);
echo $xml;
exit;
}
Cela crée probablement un problème de sécurité et vous devez vous assurer que vous prenez les mesures appropriées pour vérifier la demande.
Vérifiez la fonction post_method
dans http://taiyolab.com/mbtweet/scripts/twitterapi_call.js - un bon exemple de la méthode iframe décrite ci-dessus.
Créez deux iframes cachés (ajoutez "display: none;" au style css). Faites votre deuxième iframe pointer sur quelque chose sur votre propre domaine.
Créez un formulaire masqué, définissez sa méthode sur "post" avec target = votre première iframe et éventuellement enctype sur "multipart/form-data" (je pense que vous souhaitez effectuer POST car vous souhaitez envoyer données en plusieurs parties comme des images?)
Lorsque vous êtes prêt, envoyez le formulaire à submit () le post.
Si vous pouvez demander à l’autre domaine de renvoyer du javascript qui fera la communication interdomaine avec Iframes ( http://softwareas.com/cross-domain-communication-with-iframes ), alors vous avez de la chance peut capturer la réponse aussi bien.
Bien sûr, si vous voulez utiliser votre serveur comme proxy, vous pouvez éviter tout cela. Soumettez simplement le formulaire sur votre propre serveur, qui enverra la demande par proxy à l'autre serveur (en supposant que l'autre serveur ne soit pas configuré pour remarquer les écarts IP), obtiendra la réponse et renverra ce que vous voudrez.
Encore une chose importante à noter !!! Dans exemple ci-dessus, il est décrit comment utiliser
$.ajax({
type : 'POST',
dataType : 'json',
url : 'another-remote-server',
...
});
JQuery 1.6 et versions antérieures ont un bogue avec XHR interdomaine . Selon Firebug, aucune demande à l'exception de OPTIONS n'a été envoyée. Pas d'article. Du tout.
J'ai passé 5 heures à tester/ajuster mon code. Ajout de nombreux en-têtes sur le serveur distant (script). Sans aucun effet . Mais plus tard, j'ai mis à jour JQuery lib à 1.6.4, et tout fonctionne comme un charme.
Si vous souhaitez effectuer cette opération dans un environnement ASP.net MVC avec JQuery AJAX, procédez comme suit: (Ceci est un résumé de la solution proposée sur le fil this ).
Supposons que "caller.com" (quel que soit le site Web) doit publier sur "server.com" (une application ASP.net MVC).
Sur le fichier Web.config de l'application "server.com", ajoutez la section suivante:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="POST, GET, OPTIONS" />
</customHeaders>
</httpProtocol>
Sur le "server.com", nous aurons l'action suivante sur le contrôleur (appelé "Accueil") sur laquelle nous publierons:
[HttpPost]
public JsonResult Save()
{
//Handle the post data...
return Json(
new
{
IsSuccess = true
});
}
Ensuite, depuis "caller.com", envoyez les données d'un formulaire (avec l'ID html "formId") sur "server.com" comme suit:
$.ajax({
type: "POST",
url: "http://www.server.com/home/save",
dataType: 'json',
crossDomain: true,
data: $(formId).serialize(),
success: function (jsonResult) {
//do what ever with the reply
},
error: function (jqXHR, textStatus) {
//handle error
}
});
Je pense que le meilleur moyen est d'utiliser XMLHttpRequest (par exemple, $ .ajax (), $ .post () dans jQuery) avec l'un des polyfills de Cross-Origin Resource Sharing https://github.com/Modernizr/Modernizr/wiki/ HTML5-Cross-Browser-Polyfills # wiki-CORS
C'est une vieille question, mais certaines nouvelles technologies pourraient aider quelqu'un.
Si vous avez un accès administratif à l'autre serveur, vous pouvez utiliser le projet opensource Forge pour réaliser votre POST entre domaines. Forge fournit un wrapper JavaScript XmlHttpRequest inter-domaines qui tire parti de l'API de socket brute de Flash. Le POST peut même être fait sur TLS.
La raison pour laquelle vous avez besoin d'un accès administratif au serveur sur lequel vous postez est due au fait que vous devez fournir une stratégie inter-domaines autorisant l'accès depuis votre domaine.
Niveau élevé .... Vous devez avoir une configuration cname sur votre serveur pour que other-serve.your-server.com pointe sur other-server.com.
Votre page crée dynamiquement un iframe invisible, qui sert de transport à other-server.com. Vous devez ensuite communiquer via JS de votre page vers le serveur other-server.com et demander des rappels qui renvoient les données à votre page.
Possible mais nécessite une coordination de votre-serveur.com et autre-serveur.com
Il existe un moyen supplémentaire (utilisation de la fonctionnalité html5). Vous pouvez utiliser un proxy iframe hébergé sur cet autre domaine, vous envoyez un message à postFrame via postMessage, puis cette iframe peut faire POST demander (sur le même domaine) et redonner postMessage avec restitution à la fenêtre parent.
parent sur sender.com
var win = $('iframe')[0].contentWindow
function get(event) {
if (event.Origin === "http://reciver.com") {
// event.data is response from POST
}
}
if (window.addEventListener){
addEventListener("message", get, false)
} else {
attachEvent("onmessage", get)
}
win.postMessage(JSON.stringify({url: "URL", data: {}}),"http://reciver.com");
iframe sur reciver.com
function listener(event) {
if (event.Origin === "http://sender.com") {
var data = JSON.parse(event.data);
$.post(data.url, data.data, function(reponse) {
window.parent.postMessage(reponse, "*");
});
}
}
// don't know if we can use jQuery here
if (window.addEventListener){
addEventListener("message", listener, false)
} else {
attachEvent("onmessage", listener)
}
Cela devrait être possible avec une table personnalisée YQL + JS XHR, consultez: http://developer.yahoo.com/yql/guide/index.html
Je l'utilise pour faire des travaux côté client (js) html, fonctionne très bien.
Je sais que c'est une vieille question, mais je voulais partager mon approche. J'utilise cURL comme proxy, très facile et cohérent. Créez une page php appelée submit.php, et ajoutez le code suivant:
<?
function post($url, $data) {
$header = array("User-Agent: " . $_SERVER["HTTP_USER_AGENT"], "Content-Type: application/x-www-form-urlencoded");
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
$url = "your cross domain request here";
$data = $_SERVER["QUERY_STRING"];
echo(post($url, $data));
Ensuite, dans votre js (jQuery here):
$.ajax({
type: 'POST',
url: 'submit.php',
crossDomain: true,
data: '{"some":"json"}',
dataType: 'json',
success: function(responseData, textStatus, jqXHR) {
var value = responseData.someKey;
},
error: function (responseData, textStatus, errorThrown) {
alert('POST failed.');
}
});
Si vous avez accès au serveur interdomaine et ne souhaitez apporter aucune modification de code côté serveur, vous pouvez utiliser une bibliothèque appelée - 'xdomain'.
Comment ça marche:
Étape 1: Serveur 1: incluez la bibliothèque xdomain et configurez le domaine croisé en tant qu'esclave:
<script src="js/xdomain.min.js" slave="https://crossdomain_server/proxy.html"></script>
Étape 2: sur le serveur interdomaine, créez un fichier proxy.html et incluez le serveur 1 en tant que maître:
proxy.html:
<!DOCTYPE HTML>
<script src="js/xdomain.min.js"></script>
<script>
xdomain.masters({
"https://server1" : '*'
});
</script>
Étape 3:
Vous pouvez désormais appeler AJAX vers le fichier proxy.html en tant que point de terminaison à partir de server1. C'est contourner la demande CORS. La bibliothèque utilise en interne la solution iframe qui fonctionne avec les informations d'identification et toutes les méthodes possibles: GET, POST, etc.
Requête code ajax:
$.ajax({
url: 'https://crossdomain_server/proxy.html',
type: "POST",
data: JSON.stringify(_data),
dataType: "json",
contentType: "application/json; charset=utf-8"
})
.done(_success)
.fail(_failed)