Como envio uma solicitação POST entre domínios via JavaScript?
Notas - não deve atualizar a página e preciso pegar e analisar a resposta posteriormente.
Como envio uma solicitação POST entre domínios via JavaScript?
Notas - não deve atualizar a página e preciso pegar e analisar a resposta posteriormente.
Respostas:
Atualização: Antes de continuar, todos devem ler e entender o tutorial html5rocks no CORS. É fácil de entender e muito claro.
Se você controlar o servidor que está sendo POSTADO, simplesmente aproveite o "Padrão de compartilhamento de recursos de origem cruzada" definindo cabeçalhos de resposta no servidor. Esta resposta é discutida em outras respostas neste tópico, mas não muito claramente na minha opinião.
Em resumo, aqui está como você realiza o POST entre domínios de.com/1.html a.com/postHere.php (usando o PHP como exemplo). Nota: você só precisa definir Access-Control-Allow-Origin
para OPTIONS
solicitações NÃO - este exemplo sempre define todos os cabeçalhos para um trecho de código menor.
Na configuração postHere.php, faça o seguinte:
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;
}
Isso permite que seu script faça POST, GET e OPTIONS entre domínios. Isso ficará claro à medida que você continuar lendo ...
Configure seu POST entre domínios a partir do JS (exemplo do 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 você faz o POST na etapa 2, seu navegador envia um método "OPTIONS" para o servidor. Este é um "sniff" do navegador para ver se o servidor é legal quando você o publica. O servidor responde com um "Acesso-controle-permitir-origem" informando ao navegador que está OK para POST | GET | ORIGIN se a solicitação tiver origem em " http://from.com " ou " https://from.com ". Como o servidor está de acordo, o navegador fará uma segunda solicitação (desta vez um POST). É uma boa prática que seu cliente defina o tipo de conteúdo que está enviando - portanto, você precisará permitir isso também.
O MDN tem uma excelente descrição sobre o controle de acesso HTTP , que detalha como todo o fluxo funciona. De acordo com seus documentos, ele deve "funcionar em navegadores que suportam XMLHttpRequest entre sites". Este é um pouco enganador, no entanto, como I PENSAR únicos navegadores modernos permitem POST domínios. Eu apenas verifiquei que isso funciona com safari, chrome, FF 3.6.
Lembre-se do seguinte se você fizer isso:
400 Bad Request
a OPTIONS
pedido. e no firefox
segundo pedido de POST
nunca é feito. :(
Se você controla o servidor remoto, provavelmente deve usar o CORS, conforme descrito nesta resposta ; é suportado no IE8 e versões posteriores, e em todas as versões recentes do FF, GC e Safari. (Mas no IE8 e 9, o CORS não permitirá que você envie cookies na solicitação.)
Portanto, se você não controla o servidor remoto, ou se precisa dar suporte ao IE7, ou se precisa de cookies e precisa dar suporte ao IE8 / 9, provavelmente desejará usar uma técnica de iframe.
Aqui está o código de exemplo; Eu testei no 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();
}
Cuidado! Você não poderá ler diretamente a resposta do POST, pois o iframe existe em um domínio separado. Os quadros não podem se comunicar entre si de domínios diferentes; esta é a política de mesma origem .
Se você controla o servidor remoto, mas não pode usar o CORS (por exemplo, porque você está no IE8 / IE9 e precisa usar cookies), existem maneiras de contornar a política de mesma origem, por exemplo, usando window.postMessage
e / ou uma de várias bibliotecas que permite enviar mensagens entre quadros entre domínios em navegadores antigos:
Se você não controlar o servidor remoto, não poderá ler a resposta do POST, ponto final. Caso contrário, causaria problemas de segurança.
Pseudo-código
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();
Você provavelmente deseja estilizar o iframe, ficar oculto e absolutamente posicionado. Não há certeza de que a postagem entre sites será permitida pelo navegador, mas, nesse caso, é assim que se faz.
Mantenha simples:
POST entre domínios:
usecrossDomain: true,
não deve atualizar a página:
Não, não atualizará a página, pois oretorno de chamada assíncronosuccess
ouerror
assíncrono será chamado quando o servidor enviar a resposta.
$.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
estranhamente não tem absolutamente nada a ver com solicitações reais entre domínios. Se a solicitação for de domínio cruzado, o jquery definirá isso como verdadeiro automaticamente.
Se você tiver acesso a todos os servidores envolvidos, coloque o seguinte no cabeçalho da resposta da página solicitada no outro domínio:
PHP:
header('Access-Control-Allow-Origin: *');
Por exemplo, no código xmlrpc.php do Drupal, você faria o seguinte:
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;
}
Isso provavelmente cria um problema de segurança e você deve tomar as medidas adequadas para verificar a solicitação.
Verifique a post_method
função em http://taiyolab.com/mbtweet/scripts/twitterapi_call.js - um bom exemplo para o método iframe descrito acima.
Crie dois iframes ocultos (adicione "display: none;" ao estilo css). Faça o seu segundo iframe apontar para algo em seu próprio domínio.
Crie um formulário oculto, defina seu método como "postar" com target = seu primeiro iframe e, opcionalmente, defina enctype como "multipart / form-data" (acho que você deseja fazer o POST porque deseja enviar dados multipartes como imagens ?)
Quando estiver pronto, faça o formulário submit () o POST.
Se você conseguir que o outro domínio retorne o javascript que fará a comunicação entre domínios com iframes ( http://softwareas.com/cross-domain-communication-with-iframes ), você estará com sorte e poderá capturar a resposta também.
Obviamente, se você quiser usar seu servidor como proxy, poderá evitar tudo isso. Simplesmente envie o formulário ao seu próprio servidor, que fará proxy da solicitação para o outro servidor (supondo que o outro servidor não esteja configurado para observar discrepâncias de IP), obtenha a resposta e retorne o que quiser.
Mais uma coisa importante a ser observada !!! No exemplo acima, está descrito como usar
$.ajax({
type : 'POST',
dataType : 'json',
url : 'another-remote-server',
...
});
O JQuery 1.6 e inferior tem um erro com o XHR entre domínios. De acordo com o Firebug, nenhum pedido, exceto OPÇÕES, foi enviado. Sem POST. Em absoluto.
Passei 5 horas testando / ajustando meu código. Adicionando muitos cabeçalhos no servidor remoto (script). Sem nenhum efeito. Porém, mais tarde, atualizei a JQuery lib para a 1.6.4 e tudo funciona como um encanto.
Se você quiser fazer isso no ambiente ASP.net MVC com JQuery AJAX, siga estas etapas: (este é um resumo da solução oferecida neste segmento)
Suponha que "caller.com" (pode ser qualquer site) precise postar em "server.com" (um aplicativo ASP.net MVC)
No Web.config do aplicativo "server.com", adicione a seguinte seção:
<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>
No "server.com", executaremos a seguinte ação no controlador (chamado "Início") no qual publicaremos:
[HttpPost]
public JsonResult Save()
{
//Handle the post data...
return Json(
new
{
IsSuccess = true
});
}
Em seguida, no "caller.com", publique dados de um formulário (com o ID html "formId") em "server.com" da seguinte maneira:
$.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
}
});
Há mais uma maneira (usando o recurso html5). Você pode usar o iframe proxy hospedado nesse outro domínio, enviar uma mensagem usando postMessage para esse iframe, para que o iframe possa fazer a solicitação POST (no mesmo domínio) e o postMessage de volta com reposnse para a janela pai.
pai em 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 em 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 nível .... Você precisa ter uma configuração de cname no servidor para que other-serve.your-server.com aponte para other-server.com.
Sua página cria dinamicamente um iframe invisível, que atua como seu transporte para outro servidor.com. Você precisa se comunicar via JS da sua página para o outro servidor.com e ter retornos de chamada que retornam os dados à sua página.
Possível, mas requer coordenação entre o seu servidor e o servidor outro.
Acho que a melhor maneira é usar XMLHttpRequest (por exemplo, $ .ajax (), $ .post () no jQuery) com um dos polifills de compartilhamento de recursos de origem cruzada https://github.com/Modernizr/Modernizr/wiki/HTML5- Polyfills entre navegadores # wiki-CORS
Essa é uma pergunta antiga, mas alguma nova tecnologia pode ajudar alguém.
Se você tiver acesso administrativo ao outro servidor, poderá usar o projeto Forge de código aberto para realizar seu POST entre domínios. O Forge fornece um wrapper JavaScript XmlHttpRequest entre domínios que aproveita a API de soquete bruto do Flash. O POST pode até ser feito via TLS.
O motivo pelo qual você precisa de acesso administrativo ao servidor para o qual está postando é porque deve fornecer uma diretiva de domínio cruzado que permita o acesso do seu domínio.
Sei que essa é uma pergunta antiga, mas queria compartilhar minha abordagem. Eu uso o cURL como proxy, muito fácil e consistente. Crie uma página php chamada submit.php e adicione o seguinte código:
<?
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));
Então, em seus js (jQuery aqui):
$.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.');
}
});
Deve ser possível com uma tabela personalizada YQL + JS XHR, consulte: http://developer.yahoo.com/yql/guide/index.html
Eu o uso para fazer raspagem html no lado do cliente (js), funciona bem (eu tenho um reprodutor de áudio completo, com pesquisa na internet / playlists / letras / últimas informações fm, todos os clientes js + YQL)
CORS é para você. O CORS é "Compartilhamento de Recursos de Origem Cruzada", é uma maneira de enviar solicitações entre domínios. Agora, a API XMLHttpRequest2 e Fetch suportam o CORS e pode enviar solicitações POST e GET
O servidor precisa reivindicar o Access-Control-Allow-Origin e não pode ser definido como '*'.
E se você deseja que qualquer origem possa enviar uma solicitação para você, é necessário JSONP (também é necessário definir o Access-Control-Allow-Origin , mas pode ser '*')
Para muitas solicitações, se você não sabe escolher, acho que você precisa de um componente funcional completo para fazer isso. Deixe-me apresentar um componente simples https://github.com/Joker-Jelly/catta
Se você estiver usando um navegador moderno (> IE9, Chrome, FF, Edge etc.), recomendamos que você use um componente simples, mas bonito, https://github.com/Joker-Jelly/catta .Não tem dependência, Menos superior a 3 KB e suporta Fetch, AJAX e JSONP com a mesma sintaxe e opções de amostra mortais.
catta('./data/simple.json').then(function (res) {
console.log(res);
});
Ele também suporta todo o caminho para importar para o seu projeto, como o módulo ES6, CommonJS e até mesmo <script>
em HTML.
Se você tiver acesso ao servidor entre domínios e não quiser fazer alterações no código no servidor, poderá usar uma biblioteca chamada - 'xdomain'.
Como funciona:
Etapa 1: servidor 1: inclua a biblioteca xdomain e configure o domínio cruzado como escravo:
<script src="js/xdomain.min.js" slave="https://crossdomain_server/proxy.html"></script>
Etapa 2: no servidor entre domínios, crie um arquivo proxy.html e inclua o servidor 1 como mestre:
proxy.html:
<!DOCTYPE HTML>
<script src="js/xdomain.min.js"></script>
<script>
xdomain.masters({
"https://server1" : '*'
});
</script>
Etapa 3:
Agora, você pode fazer uma chamada AJAX para o proxy.html como ponto de extremidade do servidor1. Isso é ignorar a solicitação do CORS. A biblioteca usa internamente a solução iframe que funciona com credenciais e todos os métodos possíveis: GET, POST etc.
Consulta código 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)