Jak wysłać zapytanie POST między domenami za pomocą JavaScript?
Notatki - nie powinno odświeżać strony, a następnie muszę pobrać i przeanalizować odpowiedź.
Jak wysłać zapytanie POST między domenami za pomocą JavaScript?
Notatki - nie powinno odświeżać strony, a następnie muszę pobrać i przeanalizować odpowiedź.
Odpowiedzi:
Aktualizacja: przed kontynuowaniem każdy powinien przeczytać i zrozumieć samouczek html5rocks na temat CORS. Jest łatwy do zrozumienia i bardzo jasny.
Jeśli kontrolujesz testowany serwer POST, po prostu skorzystaj z „Standardu udostępniania zasobów między źródłami”, ustawiając nagłówki odpowiedzi na serwerze. Ta odpowiedź jest omawiana w innych odpowiedziach w tym wątku, ale moim zdaniem niezbyt jasno.
W skrócie tutaj jest, w jaki sposób osiągnąć POST między domenami z from.com/1.html do to.com/postHere.php (używając PHP jako przykładu). Uwaga: musisz ustawić tylko Access-Control-Allow-Origin
dla OPTIONS
żądań NON - ten przykład zawsze ustawia wszystkie nagłówki dla mniejszego fragmentu kodu.
W konfiguracji postHere.php:
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;
}
Umożliwia to Twojemu skryptowi wykonywanie testów POST, GET i OPCJI między domenami. Stanie się jasne, gdy będziesz czytać dalej ...
Skonfiguruj POST między domenami z JS (przykład 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.');
}
});
Po wykonaniu testu POST w kroku 2 przeglądarka wyśle do serwera metodę „OPCJE”. Jest to „wąchanie” przez przeglądarkę, aby sprawdzić, czy serwer jest fajny, kiedy go POSTINGujesz. Serwer odpowiada komunikatem „Access-Control-Allow-Origin”, który informuje przeglądarkę, że OK może POST | GET | ORIGIN, jeśli żądanie pochodzi z „ http://from.com ” lub „ https://from.com ”. Ponieważ serwer jest w porządku, przeglądarka prześle drugie żądanie (tym razem POST). Dobrą praktyką jest, aby klient ustawiał typ zawartości, którą wysyła - więc musisz również na to pozwolić.
MDN ma świetny opis dotyczący kontroli dostępu HTTP , który szczegółowo opisuje sposób działania całego przepływu. Według ich dokumentów powinien on „działać w przeglądarkach obsługujących XMLHttpRequest w różnych witrynach”. Jest to jednak trochę mylące, ponieważ MYŚLĘ, że tylko nowoczesne przeglądarki umożliwiają POST między domenami. Sprawdziłem tylko, że działa z Safari, Chrome, FF 3.6.
Jeśli to zrobisz, pamiętaj o następujących kwestiach:
400 Bad Request
na OPTIONS
życzenie. a w firefox
drugiej prośbie POST
nigdy się nie składa. :(
Jeśli kontrolujesz serwer zdalny, prawdopodobnie powinieneś użyć CORS, jak opisano w tej odpowiedzi ; jest obsługiwany w IE8 i nowszych wersjach oraz we wszystkich najnowszych wersjach FF, GC i Safari. (Ale w IE8 i 9 CORS nie zezwala na wysyłanie plików cookie w żądaniu.)
Tak więc, jeśli nie kontrolujesz zdalnego serwera lub jeśli potrzebujesz obsługi IE7 lub potrzebujesz plików cookie i musisz obsługiwać IE8 / 9, prawdopodobnie będziesz chciał użyć techniki iframe.
Oto przykładowy kod; Przetestowałem to na 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();
}
Strzec się! Nie będzie można bezpośrednio odczytać odpowiedzi testu POST, ponieważ element iframe istnieje w osobnej domenie. Ramki nie mogą komunikować się ze sobą z różnych domen; to jest polityka tego samego pochodzenia .
Jeśli kontrolujesz serwer zdalny, ale nie możesz używać CORS (np. Ponieważ korzystasz z IE8 / IE9 i musisz używać plików cookie), istnieją sposoby obejścia zasad tego samego pochodzenia, na przykład za pomocą window.postMessage
i / lub jedna z wielu bibliotek pozwalająca na wysyłanie wiadomości między ramkami między domenami w starszych przeglądarkach:
Jeśli nie kontrolujesz zdalnego serwera, nie możesz odczytać odpowiedzi testu POST, kropka. W przeciwnym razie spowodowałoby to problemy z bezpieczeństwem.
Pseudo kod
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();
Prawdopodobnie chcesz nadać styl iframe, aby był ukryty i miał absolutną pozycję. Przeglądarka nie zezwala na publikowanie w wielu witrynach, ale jeśli tak, to w jaki sposób to zrobić.
Nie komplikuj:
POST między domenami:
użyjcrossDomain: true,
nie powinien odświeżać strony:
Nie, nie odświeży strony, ponieważwywołanie zwrotnesuccess
luberror
asynchroniczne zostanie wywołane, gdy serwer odeśle odpowiedź.
$.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
dziwnie nie ma absolutnie nic wspólnego z prawdziwymi żądaniami między domenami. Jeśli żądanie dotyczy wielu domen, jquery automatycznie ustawia wartość true.
Jeśli masz dostęp do wszystkich zaangażowanych serwerów, umieść w nagłówku odpowiedzi żądanej strony w innej domenie:
PHP:
header('Access-Control-Allow-Origin: *');
Na przykład w kodzie xmlrpc.php Drupala zrobiłbyś to:
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;
}
Prawdopodobnie powoduje to problem z bezpieczeństwem i należy upewnić się, że podjęto odpowiednie środki w celu zweryfikowania żądania.
Sprawdź post_method
funkcję w http://taiyolab.com/mbtweet/scripts/twitterapi_call.js - dobry przykład opisanej powyżej metody iframe.
Utwórz dwie ukryte ramki iframe (dodaj „display: none;” do stylu css). Ustaw drugi element iframe na coś we własnej domenie.
Utwórz ukryty formularz, ustaw jego metodę na „wysyłanie” za pomocą target = twoja pierwsza ramka iframe i opcjonalnie ustaw kod na „multipart / form-data” (myślę, że chcesz zrobić POST, ponieważ chcesz wysyłać dane wieloczęściowe, takie jak zdjęcia ?)
Gdy wszystko będzie gotowe, należy wysłać formularz POST ().
Jeśli możesz poprosić drugą domenę o zwrócenie javascript, który wykona komunikację między domenami za pomocą iframe ( http://softwareas.com/cross-domain-communication-with-frrames ), to masz szczęście i możesz uchwycić odpowiedź także.
Oczywiście, jeśli chcesz używać swojego serwera jako serwera proxy, możesz tego wszystkiego uniknąć. Po prostu prześlij formularz na własny serwer, który przekaże żądanie do drugiego serwera (zakładając, że drugi serwer nie jest skonfigurowany do zauważania rozbieżności w adresie IP), uzyskaj odpowiedź i zwróć cokolwiek zechcesz.
Jeszcze jedna ważna rzecz do zapamiętania !!! W powyższym przykładzie opisano sposób użycia
$.ajax({
type : 'POST',
dataType : 'json',
url : 'another-remote-server',
...
});
JQuery 1.6 i niższe ma błąd w XDN między domenami. Według Firebug nie wysłano żadnych próśb oprócz OPCJI. Nie postuj. W ogóle.
Spędziłem 5 godzin na testowaniu / dostrajaniu mojego kodu. Dodanie dużej liczby nagłówków na zdalnym serwerze (skrypcie). Bez żadnego efektu. Ale później zaktualizowałem bibliotekę JQuery do wersji 1.6.4 i wszystko działa jak urok.
Jeśli chcesz to zrobić w środowisku ASP.net MVC z JQuery AJAX, wykonaj następujące kroki: (jest to podsumowanie rozwiązania oferowanego w tym wątku)
Załóżmy, że „caller.com” (może być dowolną witryną) musi publikować na „server.com” (aplikacja ASP.net MVC)
Na Web.config aplikacji „server.com” dodaj następującą sekcję:
<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>
Na „server.com” wykonamy następującą akcję na kontrolerze (zwaną „Home”), na której będziemy publikować:
[HttpPost]
public JsonResult Save()
{
//Handle the post data...
return Json(
new
{
IsSuccess = true
});
}
Następnie z „caller.com” wyślij dane z formularza (z identyfikatorem HTML „formId”) do „server.com” w następujący sposób:
$.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
}
});
Jest jeszcze jeden sposób (przy użyciu funkcji HTML5). Możesz użyć iframe proxy hostowanego w tej innej domenie, wysyłasz wiadomość za pomocą postMessage do tego iframe, a następnie iframe może wykonać żądanie POST (w tej samej domenie) i postMessage z powrotem z reposnse do okna nadrzędnego.
rodzic na 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 na 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)
}
Wysoki poziom .... Musisz mieć skonfigurowaną nazwę serwera na swoim serwerze, aby other-serve.your-server.com wskazywał na other-server.com.
Twoja strona dynamicznie tworzy niewidoczny element iframe, który działa jak Twój transport do other-server.com. Następnie musisz komunikować się przez JS ze swojej strony na other-server.com i mieć oddzwonienia, które zwracają dane z powrotem na twoją stronę.
Możliwe, ale wymaga koordynacji ze strony twoj-server.com i other-server.com
Myślę, że najlepszym sposobem jest użycie XMLHttpRequest (np. $ .Ajax (), $ .post () w jQuery) z jednym z wielu wypełniaczy do udostępniania zasobów między źródłami https://github.com/Modernizr/Modernizr/wiki/HTML5- Cross-Browser-Polyfills # wiki-CORS
To stare pytanie, ale jakaś nowa technologia może komuś pomóc.
Jeśli masz dostęp administracyjny do drugiego serwera, możesz użyć projektu Forource opensource, aby zrealizować test POST między domenami. Forge zapewnia międzyplatformowe opakowanie JavaScript XmlHttpRequest, które wykorzystuje interfejs API surowego gniazda Flash. POST można nawet wykonać przez TLS.
Powodem, dla którego potrzebujesz dostępu administracyjnego do serwera, na którym publikujesz POST, jest to, że musisz zapewnić zasady między domenami, które zezwalają na dostęp z Twojej domeny.
Wiem, że to stare pytanie, ale chciałem podzielić się moim podejściem. Używam cURL jako proxy, bardzo łatwe i spójne. Utwórz stronę php o nazwie subm.php i dodaj następujący kod:
<?
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));
Następnie w swoim js (tutaj jQuery):
$.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.');
}
});
Powinno to być możliwe dzięki niestandardowej tabeli YQL + JS XHR, spójrz na: http://developer.yahoo.com/yql/guide/index.html
Używam go do skrobania html po stronie klienta (js), działa dobrze (mam pełny odtwarzacz audio, z wyszukiwaniem w internecie / listach odtwarzania / tekstach / informacjach z ostatniego fm, wszystkie klienty js + YQL)
CORS jest dla Ciebie. CORS to „Udostępnianie zasobów między źródłami”, jest sposobem wysyłania żądania między domenami. Teraz XMLHttpRequest2 i Fetch API obsługują CORS i może wysyłać żądania POST i GET
Ale ma swoje ograniczenia. Serwer musi konkretnie twierdzić, że kontrola dostępu-Allow-Origin nie może być ustawiona na „*”.
A jeśli chcesz, aby jakieś pochodzenie mogło wysłać do Ciebie żądanie, potrzebujesz JSONP (musisz także ustawić Access-Control-Allow-Origin , ale może to być „*”)
W przypadku wielu sposobów żądania, jeśli nie wiesz, jak dokonać wyboru, myślę, że potrzebujesz do tego pełnego funkcjonalnego komponentu. Pozwól, że przedstawię prosty komponent https://github.com/Joker-Jelly/catta
Jeśli korzystasz z nowoczesnej przeglądarki (> IE9, Chrome, FF, Edge itp.), Bardzo polecam użycie prostego, ale pięknego komponentu https://github.com/Joker-Jelly/catta . Nie ma zależności, mniej niż 3 KB i obsługuje Fetch, AJAX i JSONP z tą samą śmiertelną składnią próbki i opcjami.
catta('./data/simple.json').then(function (res) {
console.log(res);
});
Obsługuje także importowanie do projektu, takie jak moduł ES6, CommonJS, a nawet <script>
HTML.
Jeśli masz dostęp do serwera między domenami i nie chcesz dokonywać żadnych zmian kodu po stronie serwera, możesz użyć biblioteki o nazwie - „xdomain”.
Jak to działa:
Krok 1: Serwer 1: dołącz bibliotekę xdomain i skonfiguruj domenę podrzędną jako urządzenie podrzędne:
<script src="js/xdomain.min.js" slave="https://crossdomain_server/proxy.html"></script>
Krok 2: Na serwerze między domenami utwórz plik proxy.html i dołącz serwer 1 jako wzorzec:
proxy.html:
<!DOCTYPE HTML>
<script src="js/xdomain.min.js"></script>
<script>
xdomain.masters({
"https://server1" : '*'
});
</script>
Krok 3:
Teraz możesz wykonać wywołanie AJAX do proxy.html jako punktu końcowego z serwera server1. To pomija żądanie CORS. Biblioteka wewnętrznie korzysta z rozwiązania iframe, które działa z poświadczeniami i wszystkimi możliwymi metodami: GET, POST itp.
Zapytanie kod 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)