ฉันจะส่งคำขอ 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" เพื่อบอกเบราว์เซอร์ว่าตกลงเพื่อ POST | GET | ORIGIN ถ้าคำขอมาจาก " http://from.com " หรือ " https://from.com " เนื่องจากเซิร์ฟเวอร์ตกลงกับเบราว์เซอร์จะทำการร้องขอที่สอง (ครั้งนี้เป็น POST) เป็นการดีที่จะให้ลูกค้าของคุณตั้งค่าประเภทเนื้อหาที่กำลังส่ง - ดังนั้นคุณจะต้องอนุญาตด้วยเช่นกัน
MDN มีการเขียนที่ยอดเยี่ยมเกี่ยวกับการควบคุมการเข้าถึง HTTPซึ่งมีรายละเอียดเกี่ยวกับการทำงานของโฟลว์ทั้งหมด ตามเอกสารของพวกเขามันควร "ทำงานในเบราว์เซอร์ที่สนับสนุน XMLHttpRequest ข้ามไซต์" นี่เป็นสิ่งที่ทำให้เข้าใจผิดเล็กน้อยเนื่องจากฉันคิดว่ามีเพียงเบราว์เซอร์ที่ทันสมัยเท่านั้นที่อนุญาตการข้าม POST ฉันตรวจสอบแล้วว่าใช้ได้กับซาฟารีโครเมี่ยม FF 3.6 เท่านั้น
โปรดจำไว้ว่าหากคุณทำสิ่งนี้:
400 Bad Request
ในOPTIONS
การร้องขอ และในfirefox
คำขอที่สองของPOST
ไม่เคยทำ :(
หากคุณสามารถควบคุมเซิร์ฟเวอร์ระยะไกลคุณอาจจะใช้ล ธ ที่อธิบายไว้ในคำตอบนี้ ; มันรองรับ IE8 ขึ้นไปและ FF, GC และ Safari รุ่นล่าสุดทั้งหมด (แต่ใน IE8 และ 9 CORS จะไม่อนุญาตให้คุณส่งคุกกี้ตามคำขอ)
ดังนั้นถ้าคุณ ไม่ได้ควบคุมเซิร์ฟเวอร์ระยะไกลหรือหากคุณต้องรองรับ IE7 หรือหากคุณต้องการคุกกี้และคุณต้องรองรับ 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, ช่วงเวลาได้ มันจะทำให้เกิดปัญหาด้านความปลอดภัยเป็นอย่างอื่น
pseudocode
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 เพื่อซ่อนและวางตำแหน่งอย่างแน่นอน ไม่แน่ใจว่าเบราว์เซอร์อนุญาตการโพสต์ข้ามไซต์ แต่ถ้าเป็นเช่นนั้นนี่เป็นวิธีการ
ง่าย ๆ เข้าไว้:
POST ข้ามโดเมน:
ใช้crossDomain: true,
ไม่ควรรีเฟรชหน้าเว็บ:
ไม่หน้าจะไม่รีเฟรชหน้าเว็บเนื่องจากจะมีการโทรกลับsuccess
หรือerror
async เมื่อเซิร์ฟเวอร์ส่งการตอบกลับ
$.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 ที่อธิบายข้างต้น
สร้าง iframes ที่ซ่อนอยู่สองอัน (เพิ่ม "display: none;" ในสไตล์ css) ทำให้ iframe ที่สองของคุณชี้ไปที่บางอย่างในโดเมนของคุณเอง
สร้างฟอร์มที่ซ่อนไว้ตั้งค่าวิธีการเป็น "โพสต์" โดยมีเป้าหมาย = iframe แรกของคุณและตั้งค่าประเภทเอกสารเป็น "หลายส่วน / แบบฟอร์มข้อมูล" (ฉันคิดว่าคุณต้องการทำ POST เพราะคุณต้องการส่งข้อมูลหลายส่วนเช่นรูปภาพ ?)
เมื่อพร้อมแล้วให้ส่งแบบฟอร์ม () POST
หากคุณได้รับโดเมนอื่นเพื่อส่งคืนจาวาสคริปต์ที่จะทำการสื่อสารข้ามโดเมนด้วย 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)
ใน 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" เราจะดำเนินการต่อไปนี้บนคอนโทรลเลอร์ (เรียกว่า "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) กับหนึ่งใน cross-Origin Resource Sharing polyfills https://github.com/Modernizr/Modernizr/wiki/HTML5- ข้ามเบราว์เซอร์ Polyfills # วิกิพีเดียล ธ
นี่เป็นคำถามเก่า แต่เทคโนโลยีใหม่บางอย่างอาจช่วยใครซักคน
หากคุณมีสิทธิ์การเข้าถึงระดับผู้ดูแลระบบไปยังเซิร์ฟเวอร์อื่นคุณสามารถใช้โครงการ opensource Forge เพื่อทำ POST ข้ามโดเมนได้ Forge จัดเตรียม JavaScript XmlHttpRequest wrapper ของ cross-domain ที่ใช้ประโยชน์จาก raw socket 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 ฝั่งไคลเอ็นต์ (js) ใช้งานได้ดี (ฉันมีเครื่องเล่นเสียงเต็มรูปแบบพร้อมค้นหาบนอินเทอร์เน็ต / เพลย์ลิสต์ / เนื้อเพลง / ข้อมูล fm ล่าสุดไคลเอนต์ js + YQL ทั้งหมด)
CORS สำหรับคุณ CORS คือ "Cross Origin Resource Sharing" เป็นวิธีการส่งคำขอข้ามโดเมนตอนนี้ XMLHttpRequest2 และ Fetch API รองรับทั้ง CORS และสามารถส่งคำขอ POST และ GET
แต่มันมีข้อ จำกัด เซิร์ฟเวอร์จำเป็นต้องอ้างสิทธิ์เฉพาะเจาะจงว่าAccess-Control-Allow-Originและไม่สามารถตั้งค่าเป็น '*'
และหากคุณต้องการให้ต้นกำเนิดใด ๆ สามารถส่งคำขอถึงคุณได้คุณต้องมี JSONP (ต้องตั้งค่าการควบคุมการอนุญาตให้กำเนิดแต่ต้องเป็น '*')
สำหรับวิธีการร้องขอมากมายหากคุณไม่ทราบวิธีการเลือกฉันคิดว่าคุณต้องมีองค์ประกอบการทำงานเต็มรูปแบบที่จะทำเช่นนั้นให้ฉันแนะนำองค์ประกอบง่าย ๆhttps://github.com/Joker-Jelly/catta
หากคุณกำลังใช้เบราว์เซอร์ที่ทันสมัย (> IE9, Chrome, FF, Edge และอื่น ๆ ) ขอแนะนำให้คุณใช้องค์ประกอบที่เรียบง่าย แต่สวยงามที่https://github.com/Joker-Jelly/cattaไม่มีการพึ่งพา กว่า 3KB และรองรับ Fetch, AJAX และ JSONP ด้วยไวยากรณ์และตัวอย่างตัวเลือกที่เหมือนกัน
catta('./data/simple.json').then(function (res) {
console.log(res);
});
นอกจากนี้ยังรองรับการนำเข้าสู่โครงการของคุณเช่นโมดูล ES6, CommonJS และแม้แต่<script>
ใน HTML
หากคุณสามารถเข้าถึงเซิร์ฟเวอร์ข้ามโดเมนและไม่ต้องการเปลี่ยนแปลงรหัสใด ๆ ในฝั่งเซิร์ฟเวอร์คุณสามารถใช้ไลบรารีที่เรียกว่า - 'xdomain'
มันทำงานอย่างไร:
ขั้นตอนที่ 1: เซิร์ฟเวอร์ 1: รวมไลบรารี xdomain และกำหนดค่า cross domain เป็นสลาฟ:
<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 เป็น endpoint จาก 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)