Comment envoyer une demande POST interdomaine via JavaScript?
Notes - cela ne devrait pas rafraîchir la page, et j'ai besoin de récupérer et d'analyser la réponse par la suite.
Comment envoyer une demande POST interdomaine via JavaScript?
Notes - cela ne devrait pas rafraîchir la page, et j'ai besoin de récupérer et d'analyser la réponse par la suite.
Réponses:
Mise à jour: Avant de continuer, tout le monde doit lire et comprendre le tutoriel html5rocks sur CORS . Il est facile à comprendre et très clair.
Si vous contrôlez le serveur en cours de POST, tirez simplement parti de la «norme de partage des 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 de ce fil, mais pas très clairement à mon avis.
En bref, voici comment vous pouvez effectuer le POST interdomaine 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 OPTIONS
demandes NON - cet exemple définit toujours tous les en-têtes pour un extrait de code plus petit.
Dans postHere.php, configurez les éléments suivants:
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 POST interdomaine à 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 le POST à l'étape 2, votre navigateur envoie une méthode "OPTIONS" au serveur. Ceci est un "sniff" par le navigateur pour voir si le serveur est cool avec vous en y postant. Le serveur répond avec un "Access-Control-Allow-Origin" indiquant au navigateur qu'il est d'accord pour POST | GET | ORIGIN si la demande provient de " http://from.com " ou " https://from.com ". Puisque le serveur est d'accord avec lui, le navigateur fera une 2ème demande (cette fois un POST). Il est recommandé que votre client définisse le type de contenu qu'il envoie - vous devrez donc également l'autoriser.
MDN a une grande rédaction sur le contrôle d'accès HTTP , qui explique en détail le fonctionnement de l'ensemble du flux. Selon leurs documents, cela devrait "fonctionner dans les navigateurs qui prennent en charge XMLHttpRequest intersite". C'est un peu trompeur cependant, car je pense que seuls les navigateurs modernes autorisent le POST interdomaine. Je n'ai vérifié que cela fonctionne avec safari, chrome, FF 3.6.
Gardez à l'esprit les points suivants si vous procédez ainsi:
400 Bad Request
sur OPTIONS
demande. et dans firefox
la deuxième demande de POST
n'est jamais faite. :(
Si vous contrôlez le serveur distant, vous devez 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 permettra pas d'envoyer des cookies dans la demande.)
Donc, 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 même politique d'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 même politique d'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. Sinon, cela entraînerait 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 voulez probablement styliser l'iframe, pour qu'il soit caché et absolument positionné. Je ne sais pas si la publication intersite sera autorisée par le navigateur, mais si c'est le cas, voici comment procéder.
Rester simple:
POST interdomaine:
utilisationcrossDomain: true,
ne doit pas rafraîchir la page:
Non, il ne sera pas rafraîchir la page que lesuccess
ouerror
async rappel sera appelée lorsque l'envoi de la réponse serveur.
$.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
}
});
crossDomain: true
curieusement n'a absolument rien à voir avec de vraies demandes inter-domaines. Si la demande est inter-domaines, jquery définit cela sur true de manière automatique.
Si vous avez accès à tous les serveurs impliqués, mettez 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 de prendre les mesures appropriées pour vérifier la demande.
Vérifiez la post_method
fonction dans http://taiyolab.com/mbtweet/scripts/twitterapi_call.js - un bon exemple pour la méthode iframe décrite ci-dessus.
Créez deux iframes cachés (ajoutez "display: none;" au style css). Faites en sorte que votre deuxième iframe pointe vers quelque chose sur votre propre domaine.
Créez un formulaire caché, définissez sa méthode sur "post" avec target = votre premier iframe, et définissez éventuellement enctype sur "multipart / form-data" (je pense que vous voulez faire du POST parce que vous voulez envoyer des données en plusieurs parties comme des images ?)
Lorsque vous êtes prêt, envoyez le formulaire () au POST.
Si vous pouvez obtenir l'autre domaine pour renvoyer le javascript qui fera la communication inter-domaines avec les iframes ( http://softwareas.com/cross-domain-communication-with-iframes ), alors vous avez de la chance, et vous pouvez capturer la réponse ainsi que.
Bien sûr, si vous souhaitez utiliser votre serveur comme proxy, vous pouvez éviter tout cela. Envoyez simplement le formulaire à votre propre serveur, qui procurera la demande à l'autre serveur (en supposant que l'autre serveur n'est pas configuré pour remarquer des différences IP), obtenez la réponse et retournez ce que vous voulez.
Encore une chose importante à noter !!! Dans l' exemple ci-dessus, il est décrit comment utiliser
$.ajax({
type : 'POST',
dataType : 'json',
url : 'another-remote-server',
...
});
JQuery 1.6 et inférieur a un bogue avec XHR interdomaine. Selon Firebug, aucune demande, sauf OPTIONS, n'a été envoyée. Pas d'article. Du tout.
J'ai passé 5 heures à tester / régler mon code. Ajout d'un grand nombre d'en-têtes sur le serveur distant (script). Sans aucun effet. Mais plus tard, j'ai mis à jour la bibliothèque JQuery vers 1.6.4, et tout fonctionne comme un charme.
Si vous souhaitez le faire dans un environnement ASP.net MVC avec JQuery AJAX, procédez comme suit: (il s'agit d'un résumé de la solution proposée dans ce fil)
Supposons que "caller.com" (peut être n'importe quel site Web) doit être publié sur "server.com" (une application ASP.net MVC)
Sur le 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é "Home") sur lequel nous posterons:
[HttpPost]
public JsonResult Save()
{
//Handle the post data...
return Json(
new
{
IsSuccess = true
});
}
Ensuite, à partir de "caller.com", publiez les données d'un formulaire (avec l'ID html "formId") vers "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
}
});
Il existe un autre moyen (en utilisant la fonctionnalité html5). Vous pouvez utiliser un iframe proxy hébergé sur cet autre domaine, vous envoyez un message à l'aide de postMessage à cet iframe, puis cet iframe peut effectuer une requête POST (sur le même domaine) et postMessage avec reposnse dans 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)
}
Haut niveau .... Vous devez avoir une configuration cname sur votre serveur afin que other-serve.your-server.com pointe vers other-server.com.
Votre page crée dynamiquement un iframe invisible, qui agit comme votre transport vers other-server.com. Vous devez ensuite communiquer via JS depuis votre page vers other-server.com et avoir des rappels qui renvoient les données sur votre page.
Possible mais nécessite une coordination de your-server.com et other-server.com
Je pense que la meilleure façon est d'utiliser XMLHttpRequest (par exemple $ .ajax (), $ .post () dans jQuery) avec l'un des polyfills de partage de ressources entre origines https://github.com/Modernizr/Modernizr/wiki/HTML5- Cross-Browser-Polyfills # wiki-CORS
C'est une vieille question, mais une nouvelle technologie pourrait aider quelqu'un.
Si vous disposez d'un accès administratif à l'autre serveur, vous pouvez utiliser le projet opensource Forge pour effectuer votre POST interdomaine. Forge fournit un wrapper XmlHttpRequest JavaScript inter-domaines qui tire parti de l'API de socket brut de Flash. Le POST peut même être effectué sur TLS.
La raison pour laquelle vous avez besoin d'un accès administratif au serveur sur lequel vous POSTEZ est parce que vous devez fournir une stratégie inter-domaines qui autorise l'accès à partir de votre domaine.
Je sais que c'est une vieille question, mais je voulais partager mon approche. J'utilise cURL comme proxy, très simple 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 ici):
$.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.');
}
});
Cela devrait être possible avec une table personnalisée YQL + JS XHR, jetez un œil à: http://developer.yahoo.com/yql/guide/index.html
Je l'utilise pour faire du grattage html côté client (js), fonctionne très bien (j'ai un lecteur audio complet, avec recherche sur internet / playlists / paroles / dernières informations fm, tous les clients js + YQL)
CORS est fait pour vous. CORS est "Cross Origin Resource Sharing", est un moyen d'envoyer une demande interdomaine. Maintenant, XMLHttpRequest2 et Fetch API prennent en charge CORS et peuvent envoyer à la fois des requêtes POST et GET
Mais il a ses limites. Le serveur doit revendiquer spécifiquement l' Access-Control-Allow-Origin , et il ne peut pas être défini sur '*'.
Et si vous voulez que n'importe quelle origine puisse vous envoyer une demande, vous avez besoin de JSONP (vous devez également définir Access-Control-Allow-Origin , mais peut être '*')
Pour beaucoup de demandes, si vous ne savez pas comment choisir, je pense que vous avez besoin d'un composant fonctionnel complet pour le faire. Permettez-moi de vous présenter un composant simple https://github.com/Joker-Jelly/catta
Si vous utilisez un navigateur moderne (> IE9, Chrome, FF, Edge, etc.), très vous recommande d'utiliser un composant simple mais esthétique https://github.com/Joker-Jelly/catta .Il n'a aucune dépendance, Moins de 3 Ko, et il prend en charge Fetch, AJAX et JSONP avec la même syntaxe et les options mortelles.
catta('./data/simple.json').then(function (res) {
console.log(res);
});
Il prend également en charge tout le chemin pour importer dans votre projet, comme le module ES6, CommonJS et même <script>
en HTML.
Si vous avez accès au serveur interdomaine et que vous ne souhaitez pas modifier le code côté serveur, vous pouvez utiliser une bibliothèque appelée - 'xdomain'.
Comment ça fonctionne:
É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 un 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:
Maintenant, vous pouvez effectuer un appel AJAX au proxy.html en tant que point de terminaison à partir de server1. Ceci contourne 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.
Recherchez le 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)