Как отправить междоменный запрос POST через JavaScript?
Примечания - это не должно обновлять страницу, и мне нужно получить и проанализировать ответ впоследствии.
Как отправить междоменный запрос POST через JavaScript?
Примечания - это не должно обновлять страницу, и мне нужно получить и проанализировать ответ впоследствии.
Ответы:
Обновление: Прежде чем продолжить, каждый должен прочитать и понять учебник html5rocks по CORS. Это легко понять и очень ясно.
Если вы управляете сервером POST, просто используйте «Стандарт общего доступа к ресурсам», установив заголовки ответов на сервере. Этот ответ обсуждается в других ответах в этой теме, но не очень ясно, на мой взгляд.
Вкратце, вот как вы выполняете междоменный POST от from.com/1.html до to.com/postHere.php (используя PHP в качестве примера). Примечание: вам нужно только установить Access-Control-Allow-Origin
для OPTIONS
запросов NON - этот пример всегда устанавливает все заголовки для меньшего фрагмента кода.
В 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;
}
Это позволяет вашему скрипту создавать междоменные POST, GET и OPTIONS. Это станет ясно, когда вы продолжите читать ...
Настройте свой междоменный POST из JS (пример 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.');
}
});
Когда вы выполните POST на шаге 2, ваш браузер отправит серверу метод «OPTIONS». Это «фыркание» браузером, чтобы увидеть, крут ли сервер, когда вы размещаете на нем сообщение. Сервер отвечает «Access-Control-Allow-Origin», сообщая браузеру, что он в порядке, чтобы POST | GET | ORIGIN, если запрос возник из « http://from.com » или « https://from.com ». Поскольку с сервером все в порядке, браузер сделает второй запрос (на этот раз POST). Рекомендуется, чтобы ваш клиент устанавливал тип контента, который он отправляет, так что вам также нужно это разрешить.
У MDN есть отличная статья о контроле доступа HTTP , которая подробно описывает работу всего потока. Согласно их документам, он должен «работать в браузерах, которые поддерживают межсайтовый XMLHttpRequest». Это немного вводит в заблуждение, так как я думаю, что только современные браузеры допускают междоменный POST. Я только подтвердил, что это работает с сафари, хромом, FF 3.6.
Имейте в виду следующее, если вы делаете это:
400 Bad Request
по OPTIONS
запросу. и во firefox
втором запросе POST
никогда не делается. :(
Если вы управляете удаленным сервером, вам, вероятно, следует использовать CORS, как описано в этом ответе ; он поддерживается в IE8 и более поздних версиях, а также во всех последних версиях FF, GC и Safari. (Но в IE8 и 9 CORS не позволит вам отправлять куки в запросе.)
Так что, если вы не управляете удаленным сервером, или если вам нужно поддерживать IE7, или если вам нужны файлы cookie, и вы должны поддерживать IE8 / 9, вы, вероятно, захотите использовать технику iframe.
Вот пример кода; Я проверил это на 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();
}
Осторожно! Вы не сможете напрямую прочитать ответ POST, так как iframe существует в отдельном домене. Кадры не могут общаться друг с другом из разных доменов; это политика того же происхождения .
Если вы управляете удаленным сервером, но не можете использовать CORS (например, потому что вы используете IE8 / IE9 и вам необходимо использовать куки), есть способы обойти политику одного и того же происхождения, например, с помощью window.postMessage
и / или одна из нескольких библиотек, позволяющая отправлять междоменные кросс-фреймовые сообщения в старых браузерах:
Если вы не управляете удаленным сервером, вы не можете прочитать ответ POST, точка. В противном случае это вызовет проблемы с безопасностью.
ПСЕВДОКОД
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();
Вы, вероятно, хотите, чтобы стиль iframe был скрыт и абсолютно позиционирован. Не уверен, что браузер разрешит публикацию на нескольких сайтах, но если это так, то как это сделать.
Будь проще:
междоменный пост:
использованиеcrossDomain: true,
Не следует обновлять страницу:
Нет, она не обновляет страницу, посколькуобратный вызовsuccess
илиerror
асинхронный вызов будет вызван, когда сервер отправит ответ.
$.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
странно, не имеет абсолютно никакого отношения к реальным междоменным запросам. Если запрос междоменный, jquery автоматически устанавливает значение true.
Если у вас есть доступ ко всем задействованным серверам, укажите в заголовке ответа следующую страницу для запрашиваемой страницы в другом домене:
PHP:
header('Access-Control-Allow-Origin: *');
Например, в коде Drupal xmlrpc.php вы должны сделать это:
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;
}
Это, вероятно, создает проблему безопасности, и вы должны убедиться, что вы принимаете соответствующие меры для проверки запроса.
Проверьте post_method
функцию в http://taiyolab.com/mbtweet/scripts/twitterapi_call.js - хороший пример для метода iframe, описанного выше.
Создайте два скрытых фрейма (добавьте «display: none;» в стиль css). Сделайте так, чтобы ваш второй iframe указывал на что-то в вашем домене.
Создайте скрытую форму, установите для ее метода «post» с target = вашим первым iframe и, при желании, установите для enctype «multipart / form-data» (я думаю, вы хотите сделать POST, потому что вы хотите отправлять многокомпонентные данные, такие как изображения ?)
Когда все будет готово, сделайте форму submit () POST.
Если вы можете заставить другой домен возвращать javascript, который будет выполнять междоменную связь с Iframes ( http://softwareas.com/cross-domain-communication-with-iframes ), то вам повезло, и вы можете получить ответ также.
Конечно, если вы хотите использовать свой сервер в качестве прокси, вы можете избежать всего этого. Просто отправьте форму на свой собственный сервер, который перенаправит запрос на другой сервер (при условии, что другой сервер не настроен на обнаружение несоответствия IP-адресов), получите ответ и верните все, что захотите.
Еще одна важная вещь, чтобы отметить !!! В приведенном выше примере описано, как использовать
$.ajax({
type : 'POST',
dataType : 'json',
url : 'another-remote-server',
...
});
JQuery 1.6 и ниже имеет ошибку с междоменным XHR. Согласно Firebug, никаких запросов, кроме ВАРИАНТОВ, не было отправлено. Нет пост. Совсем.
Потратил 5 часов на тестирование / настройку моего кода. Добавление большого количества заголовков на удаленный сервер (скрипт). Без какого-либо эффекта. Но позже я обновил JQuery lib до версии 1.6.4, и все работает как шарм.
Если вы хотите сделать это в среде ASP.net MVC с JQuery AJAX, выполните следующие действия: (это краткое изложение решения, предлагаемого в этой теме)
Предположим, что «caller.com» (может быть любой веб-сайт) необходимо опубликовать на «server.com» (приложение ASP.net MVC)
В файле «server.com» приложения Web.config добавьте следующий раздел:
<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>
На «server.com» у нас будет следующее действие на контроллере (называемом «Home»), на котором мы будем публиковать сообщения:
[HttpPost]
public JsonResult Save()
{
//Handle the post data...
return Json(
new
{
IsSuccess = true
});
}
Затем из «caller.com» отправьте данные из формы (с html id «formId») на «server.com» следующим образом:
$.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
}
});
Есть еще один способ (использование функции html5). Вы можете использовать прокси-сервер iframe, размещенный в этом другом домене, вы отправляете сообщение с помощью postMessage этому iframe, затем этот iframe может выполнить запрос POST (в том же домене) и postMessage обратно с reposnse в родительское окно.
родитель на 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 на 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)
}
Высокий уровень .... Вам нужно настроить cname на своем сервере, чтобы other-serve.your-server.com указывал на other-server.com.
Ваша страница динамически создает невидимый iframe, который служит вашим транспортом на other-server.com. Затем вам нужно связаться через JS со своей страницы на other-server.com и получить обратные вызовы, которые возвращают данные обратно на вашу страницу.
Возможно, но требует координации от your-server.com и other-server.com
Я думаю, что лучший способ - это использовать XMLHttpRequest (например, $ .ajax (), $ .post () в jQuery) с одним из полифайлов перекрестного общего доступа к ресурсам https://github.com/Modernizr/Modernizr/wiki/HTML5- Cross-Browser-Polyfills # вики-CORS
Это старый вопрос, но некоторые новые технологии могут помочь кому-то.
Если у вас есть административный доступ к другому серверу, вы можете использовать проект Forge с открытым исходным кодом для выполнения вашего междоменного POST. Forge предоставляет междоменную оболочку JavaScript XmlHttpRequest, которая использует API-интерфейсы необработанных сокетов Flash. POST может даже быть сделан по TLS.
Причина, по которой вам нужен административный доступ к серверу, на который вы размещаете POST, заключается в том, что вы должны предоставить междоменную политику, которая разрешает доступ из вашего домена.
Я знаю, что это старый вопрос, но я хотел поделиться своим подходом. Я использую cURL в качестве прокси, очень легко и последовательно. Создайте страницу php под названием submit.php и добавьте следующий код:
<?
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));
Затем в вашем JS (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.');
}
});
Должно быть возможно с пользовательской таблицей YQL + JS XHR, взгляните на: http://developer.yahoo.com/yql/guide/index.html
Я использую его, чтобы выполнить некоторые операции очистки jtml на стороне клиента (js), работает отлично (у меня есть полноценный аудиоплеер, с поиском в интернете / плейлистов / текстов песен / последней информации fm, все клиенты js + YQL)
CORS для вас. CORS - это «Обмен ресурсами между источниками», это способ отправки междоменного запроса. Теперь XMLHttpRequest2 и Fetch API поддерживают CORS и могут отправлять как запросы POST, так и GET.
Но у него есть свои пределы. Серверу необходимо отдельно запросить Access-Control-Allow-Origin , и его нельзя установить на «*».
И если вы хотите, чтобы любой источник мог отправить вам запрос, вам нужен JSONP (также необходимо установить Access-Control-Allow-Origin , но может быть '*')
Для большого количества запросов, если вы не знаете, как сделать выбор, я думаю, вам нужен полнофункциональный компонент, чтобы сделать это. Позвольте мне представить простой компонент https://github.com/Joker-Jelly/catta.
Если вы используете современный браузер (> IE9, Chrome, FF, Edge и т. Д.), Очень рекомендую использовать простой, но красивый компонент https://github.com/Joker-Jelly/catta . У него нет зависимости, меньше чем 3 КБ, и он поддерживает Fetch, AJAX и JSONP с тем же синтаксисом и опциями смертельного образца.
catta('./data/simple.json').then(function (res) {
console.log(res);
});
Он также поддерживает импорт в ваш проект, такой как модуль ES6, CommonJS и даже <script>
в HTML.
Если у вас есть доступ к междоменному серверу и вы не хотите вносить какие-либо изменения в код на стороне сервера, вы можете использовать библиотеку под названием - 'xdomain'.
Как это работает:
Шаг 1: сервер 1: включите библиотеку xdomain и настройте междоменный домен в качестве ведомого:
<script src="js/xdomain.min.js" slave="https://crossdomain_server/proxy.html"></script>
Шаг 2: на междоменном сервере создайте файл proxy.html и включите сервер 1 в качестве главного:
proxy.html:
<!DOCTYPE HTML>
<script src="js/xdomain.min.js"></script>
<script>
xdomain.masters({
"https://server1" : '*'
});
</script>
Шаг 3:
Теперь вы можете сделать AJAX-вызов proxy.html в качестве конечной точки с сервера server1. Это обход запроса CORS. Библиотека внутренне использует решение iframe, которое работает с учетными данными и всеми возможными методами: GET, POST и т. Д.
Запросите код 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)