Як надіслати міждоменний POST-запит через JavaScript?
Примітки - це не повинно оновлювати сторінку, і мені потрібно потім схопити та проаналізувати відповідь.
Як надіслати міждоменний POST-запит через JavaScript?
Примітки - це не повинно оновлювати сторінку, і мені потрібно потім схопити та проаналізувати відповідь.
Відповіді:
Оновлення: Перш ніж продовжувати, кожен повинен прочитати та зрозуміти підручник html5rocks на CORS. Це легко зрозуміти і дуже зрозуміло.
Якщо ви керуєте тим, що сервер буде POSTed, просто скористайтеся "стандартом перехресного походження ресурсів", встановивши заголовки відповідей на сервері. Ця відповідь обговорюється в інших відповідях у цій темі, але не дуже чітко, на мою думку.
Якщо коротко, ось як ви виконаєте крос-домен 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", повідомляючи веб-переглядачу про OK для 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 не дозволить вам надсилати файли cookie у запиті.)
Отже, якщо ви не керуєте віддаленим сервером, або якщо у вас є підтримка 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 і вам потрібно використовувати файли cookie), існують способи подолати політику одного і того ж джерела, наприклад, використовуючи 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();
Ймовірно, ви хочете, щоб стиль рамки був прихованим і абсолютно розміщеним. Не впевнений, що веб-сайт розміщуватиме веб-переглядач, але якщо це так, це зробити.
Не ускладнювати:
міждоменний POST:
використання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 встановлює це істинно автоматично.
Якщо у вас є доступ до всіх задіяних серверів, введіть у заголовку відповіді наступну сторінку, яку вимагають в іншому домені:
PHP:
header('Access-Control-Allow-Origin: *');
Наприклад, у xmlrpc.php-коді Drupal ви зробите це:
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 на щось у власному домені.
Створіть приховану форму, встановіть її метод "розміщення" з target = ваш перший iframe та, при необхідності, встановіть ентетип на "multipart / form-data" (я думаю, ви хочете зробити 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, жодних запитів, крім OPTIONS, не надсилалося. Немає посту. Зовсім.
Провів 5 годин тестування / налаштування свого коду. Додавання безлічі заголовків на віддалений сервер (скрипт). Без жодного ефекту. Але пізніше я оновив JQuery lib до 1.6.4, і все працює як шарм.
Якщо ви хочете зробити це в середовищі ASP.net MVC за допомогою JQuery AJAX, виконайте наступні кроки: (це підсумок рішення, пропонованого в цій темі)
Припустимо, що "caller.com" (може бути будь-який веб-сайт) повинен публікувати на "server.com" (додаток ASP.net MVC)
На Web.config програми "server.com" додайте наступний розділ:
<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" ми виконаємо наступну дію щодо контролера (званий "Домашня сторінка"), до якого ми будемо публікувати:
[HttpPost]
public JsonResult Save()
{
//Handle the post data...
return Json(
new
{
IsSuccess = true
});
}
Потім з "caller.com" розміщуйте дані з форми (з ідентифікатором html "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 з відкликом до батьківського вікна.
батьків на 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)
}
Високий рівень .... Вам потрібно встановити ім’я на вашому сервері, щоб other-serve.your-server.com вказував на other-server.com.
Ваша сторінка динамічно створює невидимий кадр, який виступає вашим транспортом до other-server.com. Тоді вам доведеться спілкуватися через JS зі своєї сторінки на other-server.com і мати зворотні дзвінки, які повертають дані на вашу сторінку.
Можлива, але вимагає координації з вашого веб-сайту www.server.com та інших-server.com
Я вважаю, що найкращим способом є використання XMLHttpRequest (наприклад, $ .ajax (), $ .post () у jQuery) з одним із поліфазних ресурсів для спільного використання ресурсів https://github.com/Modernizr/Modernizr/wiki/HTML5- Крос-браузер-поліфіли # wiki-CORS
Це давнє запитання, але якась нова технологія може комусь допомогти.
Якщо у вас є адміністративний доступ до іншого сервера, тоді ви можете скористатися проектом Forge Open Source для виконання вашого міждоменного POST. Forge надає міждоменну обгортку JavaScript XmlHttpRequest, яка використовує перевагу API для необробленого сокета Flash. POST може бути виконано навіть через TLS.
Причина, що вам потрібен адміністративний доступ до сервера, на який ви відправляєте повідомлення, полягає в тому, що ви повинні надати міждоменну політику, яка дозволяє доступ з вашого домену.
Я знаю, що це старе питання, але я хотів поділитися своїм підходом. Я використовую 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
Я використовую його для того, щоб зробити деякий розмір html-файлів у форматі HTML (js), добре працює (у мене є повний аудіоплеєр, з пошуком в Інтернеті / списках відтворення / текстами пісень / останньою інформацією fm, всім клієнтом js + YQL)
CORS - це для вас. CORS - "Перехресний розподіл ресурсів", це спосіб надіслати запит між доменом. Тепер XMLHttpRequest2 та 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 як кінцеву точку з сервера1. Це обхід запиту 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)