Bagaimana cara mengirim permintaan POST lintas-domain melalui JavaScript?
Catatan - seharusnya tidak menyegarkan halaman, dan saya perlu mengambil dan menguraikan respons setelahnya.
Bagaimana cara mengirim permintaan POST lintas-domain melalui JavaScript?
Catatan - seharusnya tidak menyegarkan halaman, dan saya perlu mengambil dan menguraikan respons setelahnya.
Jawaban:
Pembaruan: Sebelum melanjutkan, semua orang harus membaca dan memahami tutorial html5rocks di CORS. Mudah dimengerti dan sangat jelas.
Jika Anda mengontrol server yang POSTed, cukup leverage "Cross-Origin Resource Sharing standard" dengan menetapkan header respons di server. Jawaban ini dibahas dalam jawaban lain di utas ini, tetapi tidak terlalu jelas menurut saya.
Singkatnya di sini adalah bagaimana Anda menyelesaikan POST domain silang dari from.com/1.html ke ke.com/postHere.php (menggunakan PHP sebagai contoh). Catatan: Anda hanya perlu menetapkan permintaan Access-Control-Allow-Origin
NON OPTIONS
- contoh ini selalu menetapkan semua header untuk potongan kode yang lebih kecil.
Dalam pengaturan postHere.php berikut ini:
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;
}
Ini memungkinkan skrip Anda untuk membuat lintas domain POST, DAPATKAN dan OPSI. Ini akan menjadi jelas saat Anda terus membaca ...
Siapkan POST domain silang Anda dari JS (contoh 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.');
}
});
Ketika Anda melakukan POST di langkah 2, browser Anda akan mengirim metode "PILIHAN" ke server. Ini adalah "mengendus" oleh browser untuk melihat apakah server keren dengan Anda POSTing. Server merespons dengan "Access-Control-Allow-Origin" yang memberi tahu browser OK untuk POST | GET | ORIGIN jika permintaan berasal dari " http://from.com " atau " https://from.com ". Karena server tidak masalah dengan itu, browser akan membuat permintaan ke-2 (kali ini POST). Ini adalah praktik yang baik untuk membuat klien Anda mengatur jenis konten yang dikirim - jadi Anda harus mengizinkannya juga.
MDN memiliki banyak tulisan tentang kontrol akses HTTP , yang menjelaskan secara terperinci bagaimana keseluruhan aliran bekerja. Menurut dokumen mereka, itu harus "bekerja di browser yang mendukung XMLHttpRequest situs silang". Ini agak menyesatkan, karena saya BERPIKIR hanya browser modern yang memperbolehkan POST domain silang. Saya hanya memverifikasi ini bekerja dengan safari, chrome, FF 3.6.
Ingatlah hal-hal berikut jika Anda melakukan ini:
400 Bad Request
atas OPTIONS
permintaan. dan firefox
permintaan kedua POST
tidak pernah dibuat. :(
Jika Anda mengendalikan server jarak jauh, Anda mungkin harus menggunakan CORS, seperti yang dijelaskan dalam jawaban ini ; itu didukung di IE8 dan lebih tinggi, dan semua versi terbaru FF, GC, dan Safari. (Tetapi di IE8 dan 9, CORS tidak akan mengizinkan Anda mengirim cookie dalam permintaan.)
Jadi, jika Anda tidak mengontrol server jarak jauh, atau jika Anda harus mendukung IE7, atau jika Anda memerlukan cookie dan Anda harus mendukung IE8 / 9, Anda mungkin ingin menggunakan teknik iframe.
Berikut kode contoh; Saya mengujinya pada 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();
}
Waspadalah! Anda tidak akan dapat langsung membaca respons POST, karena iframe ada di domain yang terpisah. Frame tidak boleh saling berkomunikasi dari domain yang berbeda; ini adalah kebijakan asal yang sama .
Jika Anda mengontrol server jarak jauh tetapi Anda tidak dapat menggunakan CORS (mis. Karena Anda menggunakan IE8 / IE9 dan Anda perlu menggunakan cookie), ada beberapa cara untuk mengatasi kebijakan yang sama-asal-asalnya, misalnya dengan menggunakan window.postMessage
dan / atau salah satu dari sejumlah perpustakaan yang memungkinkan Anda mengirim pesan lintas-bingkai lintas-domain di browser lama:
Jika Anda tidak mengontrol server jarak jauh, maka Anda tidak dapat membaca respons POST, titik. Jika tidak, akan menyebabkan masalah keamanan.
Kodesemu
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();
Anda mungkin ingin gaya iframe, disembunyikan dan diposisikan benar-benar. Tidak yakin posting lintas situs akan diizinkan oleh browser, tetapi jika demikian, ini adalah bagaimana melakukannya.
Sederhana saja:
lintas-domain POST:
gunakancrossDomain: true,
seharusnya tidak me-refresh halaman:
Tidak, itu tidak akan me-refresh halaman karenapanggilan balik asyncsuccess
atauerror
akan dipanggil ketika server mengirim kembali respons.
$.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
anehnya sama sekali tidak ada hubungannya dengan permintaan lintas-domain nyata. Jika permintaan adalah lintas-domain, jquery menyetel ini ke true secara otomatis.
Jika Anda memiliki akses ke semua server yang terlibat, letakkan yang berikut di tajuk balasan untuk halaman yang diminta di domain lain:
PHP:
header('Access-Control-Allow-Origin: *');
Misalnya, dalam kode xmlrpc.php Drupal Anda akan melakukan ini:
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;
}
Ini mungkin menciptakan masalah keamanan, dan Anda harus memastikan bahwa Anda mengambil langkah-langkah yang tepat untuk memverifikasi permintaan.
Periksa post_method
fungsinya di http://taiyolab.com/mbtweet/scripts/twitterapi_call.js - contoh yang bagus untuk metode iframe yang dijelaskan di atas.
Buat dua iframe tersembunyi (tambahkan "display: none;" ke gaya css). Buat iframe kedua Anda arahkan ke sesuatu di domain Anda sendiri.
Buat formulir tersembunyi, atur metodenya menjadi "posting" dengan target = iframe pertama Anda, dan tentukan set enctype menjadi "multipart / formulir-data" (Saya pikir Anda ingin melakukan POST karena Anda ingin mengirim data multipart seperti gambar ?)
Saat siap, buat formulir kirim () POST.
Jika Anda bisa mendapatkan domain lain untuk mengembalikan javascript yang akan melakukan Komunikasi Lintas Domain Dengan Iframes ( http://softwareas.com/cross-domain-communication-with-iframes ) maka Anda beruntung, dan Anda dapat menangkap responsnya demikian juga.
Tentu saja, jika Anda ingin menggunakan server Anda sebagai proxy, Anda dapat menghindari semua ini. Cukup kirimkan formulir ke server Anda sendiri, yang akan mem-proxy permintaan ke server lain (dengan asumsi server lain tidak disiapkan untuk melihat perbedaan IP), dapatkan respons, dan kembalikan apa pun yang Anda suka.
Satu hal lagi yang perlu diperhatikan !!! Dalam contoh di atas dijelaskan cara menggunakannya
$.ajax({
type : 'POST',
dataType : 'json',
url : 'another-remote-server',
...
});
JQuery 1.6 dan yang lebih rendah memiliki bug dengan cross-domain XHR. Menurut Firebug tidak ada permintaan kecuali OPSI dikirim. Tidak ada POST. Sama sekali.
Menghabiskan 5 jam menguji / menyetel kode saya. Menambahkan banyak header di server jauh (skrip). Tanpa efek apa pun. Namun kemudian, saya memperbarui JQuery lib ke 1.6.4, dan semuanya berfungsi seperti pesona.
Jika Anda ingin melakukan ini di lingkungan ASP.net MVC dengan JQuery AJAX, ikuti langkah-langkah ini: (ini adalah ringkasan dari solusi yang ditawarkan di utas ini )
Asumsikan bahwa "caller.com" (dapat berupa situs web mana saja) perlu memposting ke "server.com" (aplikasi ASP.net MVC)
Pada Web.config aplikasi "server.com" tambahkan bagian berikut:
<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>
Di "server.com", kami akan melakukan tindakan berikut pada pengontrol (disebut "Beranda") yang akan kami poskan:
[HttpPost]
public JsonResult Save()
{
//Handle the post data...
return Json(
new
{
IsSuccess = true
});
}
Kemudian dari "caller.com", posting data dari formulir (dengan id html "formId") ke "server.com" sebagai berikut:
$.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
}
});
Ada satu cara lagi (menggunakan fitur html5). Anda dapat menggunakan proxy iframe yang dihosting di domain lain itu, Anda mengirim pesan menggunakan postMessage ke iframe itu, lalu iframe dapat melakukan permintaan POST (pada domain yang sama) dan postMessage kembali dengan reposnse ke jendela induk.
induk di 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 di 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)
}
Tingkat tinggi .... Anda harus memiliki pengaturan cname di server Anda sehingga other-serve.your-server.com menunjuk ke other-server.com.
Halaman Anda secara dinamis membuat iframe yang tidak terlihat, yang bertindak sebagai transportasi Anda ke server lain-server.com. Anda kemudian harus berkomunikasi melalui JS dari halaman Anda ke server- lain.com dan memiliki panggilan balik yang mengembalikan data kembali ke halaman Anda.
Mungkin tetapi membutuhkan koordinasi dari server- Anda.com dan server- lain.com
Saya pikir cara terbaik adalah dengan menggunakan XMLHttpRequest (mis. $ .Ajax (), $ .post () di jQuery) dengan salah satu polyfills Berbagi Sumber Daya Lintas-Negara https://github.com/Modernizr/Modernizr/wiki/HTML5- Cross-Browser-Polyfill # wiki-CORS
Ini adalah pertanyaan lama, tetapi beberapa teknologi baru mungkin bisa membantu seseorang.
Jika Anda memiliki akses administratif ke server lain, maka Anda dapat menggunakan proyek opensource Forge untuk menyelesaikan POST lintas-domain Anda. Forge menyediakan pembungkus JavaScript lintas domain XmlHttpRequest yang memanfaatkan API soket mentah Flash. POST bahkan dapat dilakukan melalui TLS.
Alasan Anda memerlukan akses administratif ke server tempat Anda POSTing adalah karena Anda harus memberikan kebijakan lintas domain yang mengizinkan akses dari domain Anda.
Saya tahu ini adalah pertanyaan lama, tetapi saya ingin membagikan pendekatan saya. Saya menggunakan cURL sebagai proxy, sangat mudah dan konsisten. Buat halaman php yang disebut submit.php, dan tambahkan kode berikut:
<?
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));
Kemudian, di js Anda (jQuery sini):
$.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.');
}
});
Seharusnya dimungkinkan dengan tabel khusus YQL + JS XHR, lihat: http://developer.yahoo.com/yql/guide/index.html
Saya menggunakannya untuk melakukan pengikisan html sisi klien (js), berfungsi dengan baik (Saya memiliki pemutar audio lengkap, dengan pencarian di internet / daftar putar / lirik / informasi fm terakhir, semua klien js + YQL)
CORS adalah untuk Anda. CORS adalah "Cross Origin Resource Sharing", adalah cara untuk mengirim permintaan lintas domain. Sekarang XMLHttpRequest2 dan Fetch API keduanya mendukung CORS, dan ia dapat mengirim permintaan POST dan GET
Tetapi ia memiliki batasnya. Server harus mengklaim secara khusus Access-Control-Allow-Origin , dan itu tidak dapat diatur ke '*'.
Dan jika Anda ingin asal mana pun dapat mengirim permintaan kepada Anda, Anda perlu JSONP (juga perlu mengatur Access-Control-Allow-Origin , tetapi bisa menjadi '*')
Untuk banyak cara permintaan jika Anda tidak tahu cara memilih, saya pikir Anda memerlukan komponen fungsional penuh untuk melakukan itu. Mari saya perkenalkan komponen sederhana https://github.com/Joker-Jelly/catta
Jika Anda menggunakan browser modern (> IE9, Chrome, FF, Edge, dll.), Sangat Merekomendasikan Anda untuk menggunakan komponen yang sederhana namun cantik https://github.com/Joker-Jelly/catta . Tidak memiliki ketergantungan, Lebih sedikit dari 3KB, dan mendukung Fetch, AJAX dan JSONP dengan sintaks dan opsi sampel yang sama mematikan.
catta('./data/simple.json').then(function (res) {
console.log(res);
});
Ini juga mendukung semua cara untuk mengimpor ke proyek Anda, seperti modul ES6, CommonJS dan bahkan <script>
dalam HTML.
Jika Anda memiliki akses ke server lintas domain dan tidak ingin melakukan perubahan kode di sisi server, Anda dapat menggunakan perpustakaan yang disebut - 'xdomain'.
Bagaimana itu bekerja:
Langkah 1: server 1: sertakan pustaka xdomain dan konfigurasikan domain silang sebagai budak:
<script src="js/xdomain.min.js" slave="https://crossdomain_server/proxy.html"></script>
Langkah 2: pada server lintas domain, buat file proxy.html dan sertakan server 1 sebagai master:
proxy.html:
<!DOCTYPE HTML>
<script src="js/xdomain.min.js"></script>
<script>
xdomain.masters({
"https://server1" : '*'
});
</script>
Langkah 3:
Sekarang, Anda dapat membuat panggilan AJAX ke proxy.html sebagai titik akhir dari server1. Ini melewati permintaan CORS. Perpustakaan secara internal menggunakan solusi iframe yang bekerja dengan Kredensial dan semua metode yang mungkin: DAPATKAN, POST dll.
Kode ajax kueri:
$.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)