Come posso inviare una richiesta POST tra domini tramite JavaScript?
Note: non dovrebbe aggiornare la pagina e dopo devo prendere e analizzare la risposta.
Come posso inviare una richiesta POST tra domini tramite JavaScript?
Note: non dovrebbe aggiornare la pagina e dopo devo prendere e analizzare la risposta.
Risposte:
Aggiornamento: prima di continuare, tutti dovrebbero leggere e comprendere il tutorial html5rocks su CORS. È facile da capire e molto chiaro.
Se controlli il server POST, usa semplicemente lo "Standard di condivisione delle risorse tra le origini" impostando le intestazioni di risposta sul server. Questa risposta è discussa in altre risposte in questo thread, ma non molto chiaramente secondo me.
In breve, ecco come realizzare il POST tra domini da da.com/1.html a a.com/postHere.php (usando PHP come esempio). Nota: è necessario impostare solo Access-Control-Allow-Origin
per OPTIONS
richieste NON : in questo esempio vengono sempre impostate tutte le intestazioni per uno snippet di codice più piccolo.
In postHere.php imposta quanto segue:
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;
}
Ciò consente al tuo script di creare POST, GET e OPTIONS tra domini. Questo diventerà chiaro mentre continui a leggere ...
Imposta il tuo POST interdominio da JS (esempio 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.');
}
});
Quando esegui il POST al passaggio 2, il browser invierà un metodo "OPTIONS" al server. Questo è un "annusare" dal browser per vedere se il server è bello con te POST. Il server risponde con un "Access-Control-Allow-Origin" che dice al browser che è OK a POST | GET | ORIGIN se la richiesta proviene da " http://from.com " o " https://from.com ". Poiché il server è OK, il browser farà una seconda richiesta (questa volta un POST). È buona norma avere il client impostato il tipo di contenuto che sta inviando, quindi è necessario consentire anche quello.
MDN ha un ottimo resoconto sul controllo degli accessi HTTP , che spiega in dettaglio come funziona l'intero flusso. Secondo i loro documenti, dovrebbe "funzionare nei browser che supportano XMLHttpRequest tra siti". Questo è un po 'fuorviante, dato che PENSO che solo i browser moderni consentano il POST tra domini. Ho verificato che funziona solo con Safari, Chrome, FF 3.6.
Tieni presente quanto segue se esegui questa operazione:
400 Bad Request
su OPTIONS
richiesta. e nella firefox
seconda richiesta di POST
non viene mai effettuata. :(
Se controlli il server remoto, dovresti probabilmente usare CORS, come descritto in questa risposta ; è supportato in IE8 e versioni successive e in tutte le versioni recenti di FF, GC e Safari. (Ma in IE8 e 9, CORS non ti consentirà di inviare cookie nella richiesta.)
Quindi, se non controlli il server remoto, o se devi supportare IE7, o se hai bisogno di cookie e devi supportare IE8 / 9, probabilmente vorrai usare una tecnica iframe.
Ecco un codice di esempio; L'ho testato su 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();
}
Attenzione! Non sarai in grado di leggere direttamente la risposta del POST, poiché l'iframe esiste su un dominio separato. I frame non sono autorizzati a comunicare tra loro da domini diversi; questa è la stessa politica di origine .
Se controlli il server remoto ma non puoi utilizzare CORS (ad es. Perché sei su IE8 / IE9 e devi usare i cookie), ci sono modi per aggirare la stessa politica di origine, ad esempio usando window.postMessage
e / o una delle numerose librerie che ti consentono di inviare messaggi cross-frame tra domini nei browser più vecchi:
Se non controlli il server remoto, non puoi leggere la risposta del POST, punto. Altrimenti causerebbe problemi di sicurezza.
pseudocodice
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();
Probabilmente vuoi dare uno stile all'iframe, essere nascosto e assolutamente posizionato. Non sono sicuri che il browser consentirà la pubblicazione su più siti, ma in tal caso, ecco come farlo.
Mantienilo semplice:
POST tra domini:
utilizzarecrossDomain: true,
non dovrebbe aggiornare la pagina:
No, non si aggiorna la pagina comesuccess
oerror
asincrono callback verrà chiamata quando il server di invio di nuovo la risposta.
$.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
stranamente non ha assolutamente nulla a che fare con le richieste reali tra domini. Se la richiesta è tra domini, jquery lo imposta su true automagicamente.
Se hai accesso a tutti i server coinvolti, inserisci quanto segue nell'intestazione della risposta per la pagina richiesta nell'altro dominio:
PHP:
header('Access-Control-Allow-Origin: *');
Ad esempio, nel codice xmlrpc.php di Drupal faresti questo:
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;
}
Questo probabilmente crea un problema di sicurezza e dovresti assicurarti di prendere le misure appropriate per verificare la richiesta.
Controlla la post_method
funzione in http://taiyolab.com/mbtweet/scripts/twitterapi_call.js - un buon esempio per il metodo iframe sopra descritto.
Crea due iframe nascosti (aggiungi "display: none;" allo stile css). Fai in modo che il tuo secondo iframe punti a qualcosa sul tuo dominio.
Crea un modulo nascosto, imposta il suo metodo su "pubblica" con target = il tuo primo iframe e, facoltativamente, imposta il tipo su "multipart / form-data" (Sto pensando che vuoi fare POST perché vuoi inviare dati multipart come immagini ?)
Quando sei pronto, invia il modulo submit () il POST.
Se riesci a ottenere l'altro dominio per restituire javascript che farà comunicazione tra domini con Iframe ( http://softwareas.com/cross-domain-communication-with-iframes ), allora sei fortunato e puoi catturare la risposta anche.
Naturalmente, se si desidera utilizzare il server come proxy, è possibile evitare tutto ciò. Invia semplicemente il modulo al tuo server, che eseguirà il proxy della richiesta all'altro server (supponendo che l'altro server non sia impostato per rilevare discrepanze IP), ottieni la risposta e restituisci quello che preferisci.
Un'altra cosa importante da notare !!! Nel esempio sopra è descritto come utilizzare
$.ajax({
type : 'POST',
dataType : 'json',
url : 'another-remote-server',
...
});
JQuery 1.6 e precedenti hanno un bug con XHR tra domini. Secondo Firebug non sono state inviate richieste tranne OPTIONS. Nessun post. Affatto.
Ho trascorso 5 ore testando / ottimizzando il mio codice. Aggiunta di molte intestazioni sul server remoto (script). Senza alcun effetto. Ma più tardi, ho aggiornato JQuery lib alla 1.6.4 e tutto funziona come un fascino.
Se si desidera eseguire questa operazione nell'ambiente ASP.net MVC con JQuery AJAX, attenersi alla seguente procedura: (questo è un riepilogo della soluzione offerta in questo thread)
Supponiamo che "caller.com" (può essere qualsiasi sito Web) debba pubblicare su "server.com" (un'applicazione ASP.net MVC)
Sul Web.config dell'app "server.com" aggiungi la seguente sezione:
<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>
Su "server.com" avremo la seguente azione sul controller (chiamata "Home") su cui pubblicheremo:
[HttpPost]
public JsonResult Save()
{
//Handle the post data...
return Json(
new
{
IsSuccess = true
});
}
Quindi da "caller.com", pubblica i dati da un modulo (con l'id html "formId") su "server.com" come segue:
$.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
}
});
C'è un altro modo (usando la funzione html5). È possibile utilizzare iframe proxy ospitato su quell'altro dominio, inviare un messaggio utilizzando postMessage a tale iframe, quindi quell'iframe può eseguire la richiesta POST (sullo stesso dominio) e postMessage di nuovo con reposnse nella finestra padre.
genitore su mittente.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 su 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)
}
Alto livello .... Devi avere una configurazione cname sul tuo server in modo che other-serve.your-server.com punti ad other-server.com.
La tua pagina crea dinamicamente un iframe invisibile, che funge da trasporto verso other-server.com. Devi quindi comunicare via JS dalla tua pagina ad other-server.com e avere richiamate che restituiscono i dati alla tua pagina.
Possibile ma richiede il coordinamento da your-server.com e other-server.com
Penso che il modo migliore sia usare XMLHttpRequest (es. $ .Ajax (), $ .post () in jQuery) con uno dei polyfill di Cross-Origin Resource Sharing https://github.com/Modernizr/Modernizr/wiki/HTML5- Cross-Browser-polyfills # wiki-CORS
Questa è una vecchia domanda, ma alcune nuove tecnologie potrebbero aiutare qualcuno.
Se si dispone dell'accesso amministrativo all'altro server, è possibile utilizzare il progetto Openource Forge per realizzare il POST tra domini. Forge fornisce un wrapper XmlHttpRequest JavaScript tra domini che sfrutta l'API raw socket di Flash. Il POST può anche essere eseguito su TLS.
Il motivo per cui hai bisogno dell'accesso amministrativo al server a cui stai POSTANDO è perché devi fornire una politica tra domini che consenta l'accesso dal tuo dominio.
So che questa è una vecchia domanda, ma volevo condividere il mio approccio. Uso cURL come proxy, molto semplice e coerente. Crea una pagina php chiamata submit.php e aggiungi il seguente codice:
<?
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));
Quindi, nel tuo js (jQuery qui):
$.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.');
}
});
Dovrebbe essere possibile con una tabella personalizzata YQL + JS XHR, dai un'occhiata a: http://developer.yahoo.com/yql/guide/index.html
Lo uso per eseguire alcuni scraping html lato client (js), funziona bene (ho un lettore audio completo, con ricerca su internet / playlist / testi / informazioni fm ultime, tutti i client js + YQL)
CORS è per te. CORS è "Condivisione delle risorse tra origini", è un modo per inviare richieste tra domini. Ora XMLHttpRequest2 e l'API Fetch supportano entrambi CORS e possono inviare sia richieste POST che GET
Ma ha i suoi limiti. Il server deve rivendicare in modo specifico Access-Control-Allow-Origin e non può essere impostato su '*'.
E se vuoi che qualsiasi origine possa inviarti una richiesta, hai bisogno di JSONP (devi anche impostare Access-Control-Allow-Origin , ma può essere '*')
Per molte modalità di richiesta se non sai come scegliere, penso che tu abbia bisogno di un componente completamente funzionale per farlo. Permettimi di presentare un semplice componente https://github.com/Joker-Jelly/catta
Se stai utilizzando un browser moderno (> IE9, Chrome, FF, Edge, ecc.), Consiglio vivamente di utilizzare un componente semplice ma di bellezza https://github.com/Joker-Jelly/catta . Non ha dipendenza, Meno di 3 KB e supporta Fetch, AJAX e JSONP con la stessa sintassi e opzioni micidiali.
catta('./data/simple.json').then(function (res) {
console.log(res);
});
Supporta inoltre l'importazione nel tuo progetto, come il modulo ES6, CommonJS e persino <script>
in HTML.
Se hai accesso al server interdominio e non desideri apportare modifiche al codice sul lato server, puoi utilizzare una libreria chiamata "xdomain".
Come funziona:
Passaggio 1: server 1: includere la libreria xdomain e configurare il dominio incrociato come slave:
<script src="js/xdomain.min.js" slave="https://crossdomain_server/proxy.html"></script>
Passaggio 2: sul server interdominio, creare un file proxy.html e includere il server 1 come master:
proxy.html:
<!DOCTYPE HTML>
<script src="js/xdomain.min.js"></script>
<script>
xdomain.masters({
"https://server1" : '*'
});
</script>
Passaggio 3:
Ora è possibile effettuare una chiamata AJAX a proxy.html come endpoint dal server1. Questo è bypassare la richiesta CORS. La libreria utilizza internamente una soluzione iframe che funziona con credenziali e tutti i metodi possibili: GET, POST ecc.
Richiesta codice 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)