Làm cách nào để gửi yêu cầu POST tên miền chéo qua JavaScript?
Ghi chú - không nên làm mới trang và tôi cần lấy và phân tích phản hồi sau đó.
Làm cách nào để gửi yêu cầu POST tên miền chéo qua JavaScript?
Ghi chú - không nên làm mới trang và tôi cần lấy và phân tích phản hồi sau đó.
Câu trả lời:
Cập nhật: Trước khi tiếp tục, mọi người nên đọc và hiểu hướng dẫn html5rocks trên CORS. Nó rất dễ hiểu và rất rõ ràng.
Nếu bạn điều khiển máy chủ được POST, chỉ cần tận dụng "Tiêu chuẩn chia sẻ tài nguyên nguồn gốc chéo" bằng cách đặt các tiêu đề phản hồi trên máy chủ. Câu trả lời này được thảo luận trong các câu trả lời khác trong chủ đề này, nhưng theo tôi thì không rõ ràng lắm.
Nói tóm lại, đây là cách bạn thực hiện POST tên miền chéo từ from.com/1.html đến to.com/postHere.php (sử dụng PHP làm ví dụ). Lưu ý: bạn chỉ cần đặt Access-Control-Allow-Origin
cho OPTIONS
các yêu cầu NON - ví dụ này luôn đặt tất cả các tiêu đề cho một đoạn mã nhỏ hơn.
Trong thiết lập postHere.php như sau:
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;
}
Điều này cho phép tập lệnh của bạn thực hiện POST, GET và TÙY CHỌN tên miền chéo. Điều này sẽ trở nên rõ ràng khi bạn tiếp tục đọc ...
Thiết lập POST tên miền chéo của bạn từ JS (ví dụ 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.');
}
});
Khi bạn thực hiện POST ở bước 2, trình duyệt của bạn sẽ gửi phương thức "TÙY CHỌN" đến máy chủ. Đây là một "sniff" của trình duyệt để xem liệu máy chủ có tuyệt vời với bạn POST với nó không. Máy chủ phản hồi với "Kiểm soát truy cập-Cho phép-Xuất xứ" cho trình duyệt biết OK với POST | GET | ORIGIN nếu yêu cầu bắt nguồn từ " http://from.com " hoặc " https://from.com ". Vì máy chủ ổn với nó, trình duyệt sẽ đưa ra yêu cầu thứ 2 (lần này là POST). Đó là một thực tế tốt để khách hàng của bạn đặt loại nội dung mà nó đang gửi - vì vậy bạn cũng cần phải cho phép điều đó.
MDN có một bài viết tuyệt vời về kiểm soát truy cập HTTP , đi sâu vào chi tiết về cách toàn bộ hoạt động của luồng. Theo tài liệu của họ, nó sẽ "hoạt động trong các trình duyệt hỗ trợ XMLHttpRequest chéo trang". Tuy nhiên, điều này hơi sai lệch, vì tôi nghĩ rằng chỉ các trình duyệt hiện đại mới cho phép POST tên miền chéo. Tôi chỉ xác minh điều này hoạt động với safari, chrome, FF 3.6.
Hãy ghi nhớ những điều sau nếu bạn làm điều này:
400 Bad Request
theo OPTIONS
yêu cầu. và trong firefox
yêu cầu thứ hai POST
không bao giờ được thực hiện. :(
Nếu bạn điều khiển máy chủ từ xa, có lẽ bạn nên sử dụng CORS, như được mô tả trong câu trả lời này ; nó được hỗ trợ trong IE8 trở lên và tất cả các phiên bản gần đây của FF, GC và Safari. (Nhưng trong IE8 và 9, CORS sẽ không cho phép bạn gửi cookie trong yêu cầu.)
Vì vậy, nếu bạn không điều khiển máy chủ từ xa hoặc nếu bạn phải hỗ trợ IE7 hoặc nếu bạn cần cookie và bạn phải hỗ trợ IE8 / 9, có lẽ bạn sẽ muốn sử dụng kỹ thuật iframe.
Đây là mã mẫu; Tôi đã thử nghiệm nó trên 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();
}
Coi chừng! Bạn sẽ không thể đọc trực tiếp phản hồi của POST, vì iframe tồn tại trên một tên miền riêng. Các khung không được phép liên lạc với nhau từ các miền khác nhau; đây là chính sách cùng nguồn gốc .
Nếu bạn điều khiển máy chủ từ xa nhưng bạn không thể sử dụng CORS (ví dụ: vì bạn đang sử dụng IE8 / IE9 và bạn cần sử dụng cookie), có nhiều cách để khắc phục chính sách cùng nguồn gốc, ví dụ như bằng cách sử dụng window.postMessage
và / hoặc một trong số các thư viện cho phép bạn gửi tin nhắn khung chéo tên miền trong các trình duyệt cũ hơn:
Nếu bạn không điều khiển máy chủ từ xa, thì bạn không thể đọc phản hồi của POST, period. Nó sẽ gây ra vấn đề an ninh khác.
Mã giả
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();
Bạn có thể muốn tạo kiểu cho iframe, được ẩn và định vị tuyệt đối. Không chắc chắn việc đăng trang chéo sẽ được trình duyệt cho phép, nhưng nếu vậy, đây là cách thực hiện.
Giữ cho nó đơn giản:
POST tên miền chéo:
sử dụngcrossDomain: true,
không nên làm mới trang:
Không, nó sẽ không làm mới trang vìcuộc gọi lạisuccess
hoặcerror
async sẽ được gọi khi máy chủ gửi lại phản hồi.
$.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
kỳ quặc hoàn toàn không có gì để làm với các yêu cầu tên miền thực sự. Nếu yêu cầu là tên miền chéo, jquery đặt điều này thành đúng tự động.
Nếu bạn có quyền truy cập vào tất cả các máy chủ liên quan, hãy đặt phần sau vào tiêu đề trả lời cho trang được yêu cầu trong tên miền khác:
PHP:
header('Access-Control-Allow-Origin: *');
Ví dụ: trong mã xmlrpc.php của Drupal, bạn sẽ làm điều này:
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;
}
Điều này có thể tạo ra một vấn đề bảo mật và bạn nên đảm bảo rằng bạn thực hiện các biện pháp thích hợp để xác minh yêu cầu.
Kiểm tra post_method
chức năng trong http://taiyolab.com/mbtweet/scripts/twitterapi_call.js - một ví dụ hay cho phương thức iframe được mô tả ở trên.
Tạo hai iframe ẩn (thêm "display: none;" vào kiểu css). Đặt iframe thứ hai của bạn trỏ đến một cái gì đó trên tên miền của riêng bạn.
Tạo một biểu mẫu ẩn, đặt phương thức của nó thành "đăng" với target = iframe đầu tiên của bạn và tùy ý đặt enctype thành "nhiều dữ liệu / biểu mẫu dữ liệu" (Tôi nghĩ rằng bạn muốn thực hiện POST vì bạn muốn gửi dữ liệu nhiều phần như hình ảnh ?)
Khi đã sẵn sàng, hãy tạo biểu mẫu gửi () POST.
Nếu bạn có thể khiến tên miền khác trả lại javascript sẽ thực hiện Giao tiếp tên miền chéo với Iframes ( http://softwareas.com/cross-domain-cransication-with-iframes ) thì bạn rất may mắn và bạn có thể nắm bắt được phản hồi cũng.
Tất nhiên, nếu bạn muốn sử dụng máy chủ của mình làm proxy, bạn có thể tránh tất cả điều này. Chỉ cần gửi biểu mẫu đến máy chủ của riêng bạn, nó sẽ ủy quyền yêu cầu đến máy chủ khác (giả sử máy chủ khác không được thiết lập để nhận thấy sự khác biệt IP), nhận phản hồi và trả lại bất cứ điều gì bạn muốn.
Một điều quan trọng hơn cần lưu ý !!! Trong ví dụ trên, nó mô tả cách sử dụng
$.ajax({
type : 'POST',
dataType : 'json',
url : 'another-remote-server',
...
});
JQuery 1.6 trở xuống có lỗi với XHR tên miền chéo. Theo Fireorms, không có yêu cầu nào ngoại trừ TÙY CHỌN được gửi. Không có bài đăng. Ở tất cả.
Đã dành 5 giờ để kiểm tra / điều chỉnh mã của tôi. Thêm rất nhiều tiêu đề trên máy chủ từ xa (script). Không có tác dụng. Nhưng sau đó, tôi đã cập nhật lib JQuery lên 1.6.4 và mọi thứ hoạt động như một nét quyến rũ.
Nếu bạn muốn làm điều này trong môi trường MVC của ASP.net với JQuery AJAX, hãy làm theo các bước sau: (đây là tóm tắt về giải pháp được cung cấp tại chuỗi này )
Giả sử rằng "caller.com" (có thể là bất kỳ trang web nào) cần đăng lên "server.com" (một ứng dụng ASP.net MVC)
Trên Web.config của ứng dụng "server.com", thêm phần sau:
<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>
Trên "server.com", chúng tôi sẽ có hành động sau trên bộ điều khiển (được gọi là "Trang chủ") mà chúng tôi sẽ đăng:
[HttpPost]
public JsonResult Save()
{
//Handle the post data...
return Json(
new
{
IsSuccess = true
});
}
Sau đó, từ "caller.com", đăng dữ liệu từ một biểu mẫu (với id html "formId") lên "server.com" như sau:
$.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
}
});
Có một cách nữa (sử dụng tính năng html5). Bạn có thể sử dụng proxy iframe được lưu trữ trên tên miền khác đó, bạn gửi tin nhắn bằng postMessage đến iframe đó, iframe đó có thể thực hiện yêu cầu POST (trên cùng một tên miền) và postMessage trở lại với cửa sổ cha mẹ.
phụ huynh trên 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 trên 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)
}
Cấp độ cao .... Bạn cần phải có một thiết lập tên trên máy chủ của mình để other-serve.your-server.com trỏ đến other-server.com.
Trang của bạn tự động tạo một iframe vô hình, hoạt động như vận chuyển của bạn đến other-server.com. Sau đó, bạn phải liên lạc qua JS từ trang của bạn đến other-server.com và có các cuộc gọi lại để trả lại dữ liệu cho trang của bạn.
Có thể nhưng cần có sự phối hợp từ your-server.com và other-server.com
Tôi nghĩ cách tốt nhất là sử dụng XMLHttpRequest (ví dụ: $ .ajax (), $ .post () trong jQuery) với một trong các polyfills Chia sẻ tài nguyên nguồn gốc https://github.com/Modernizr/Modernizr/wiki/HTML5- Đa trình duyệt-Polyfills # wiki-CORS
Đây là một câu hỏi cũ, nhưng một số công nghệ mới có thể giúp đỡ ai đó.
Nếu bạn có quyền truy cập quản trị vào máy chủ khác thì bạn có thể sử dụng dự án Forge mã nguồn mở để thực hiện POST tên miền chéo của mình. Forge cung cấp trình bao bọc JavaScript XmlHttpRequest tên miền chéo, tận dụng API ổ cắm thô của Flash. POST thậm chí có thể được thực hiện qua TLS.
Lý do bạn cần quyền truy cập quản trị vào máy chủ mà bạn đang ĐĂNG là vì bạn phải cung cấp chính sách tên miền chéo cho phép truy cập từ tên miền của bạn.
Tôi biết đây là một câu hỏi cũ, nhưng tôi muốn chia sẻ cách tiếp cận của mình. Tôi sử dụng cURL như một proxy, rất dễ dàng và nhất quán. Tạo một trang php có tên là submit.php và thêm đoạn mã sau:
<?
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));
Sau đó, trong js của bạn (jQuery ở đây):
$.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.');
}
});
Nếu có thể với bảng tùy chỉnh YQL + JS XHR, hãy xem: http://developer.yahoo.com/yql/guide/index.html
Tôi sử dụng nó để thực hiện một số thao tác html (js) phía máy khách, hoạt động tốt (Tôi có trình phát âm thanh đầy đủ, với tìm kiếm trên internet / danh sách phát / lời bài hát / thông tin fm cuối cùng, tất cả ứng dụng khách js + YQL)
CORS là dành cho bạn. CORS là "Chia sẻ tài nguyên nguồn gốc chéo", là một cách để gửi yêu cầu tên miền chéo. Bây giờ, cả XMLHttpRequest2 và Fetch API đều hỗ trợ CORS và nó có thể gửi cả yêu cầu POST và GET
Nhưng nó có giới hạn của nó. Máy chủ cần xác nhận quyền truy cập cụ thể Kiểm soát truy cập-Cho phép-Xuất xứ và không thể được đặt thành '*'.
Và nếu bạn muốn bất kỳ nguồn gốc nào có thể gửi yêu cầu cho bạn, bạn cần JSONP (cũng cần đặt Access-Control-Allow-Origin , nhưng có thể là '*')
Đối với nhiều cách yêu cầu nếu bạn không biết cách lựa chọn, tôi nghĩ bạn cần một thành phần chức năng đầy đủ để làm điều đó. Hãy để tôi giới thiệu một thành phần đơn giản https://github.com/Joker-Jelly/catta
Nếu bạn đang sử dụng trình duyệt hiện đại (> IE9, Chrome, FF, Edge, v.v.), Rất khuyên bạn nên sử dụng một thành phần đơn giản nhưng đẹp mắt https://github.com/Joker-Jelly/catta . Nó không phụ thuộc, Ít hơn hơn 3KB và nó hỗ trợ Fetch, AJAX và JSONP với cùng các tùy chọn và cú pháp mẫu chết người.
catta('./data/simple.json').then(function (res) {
console.log(res);
});
Nó cũng hỗ trợ tất cả các cách để nhập vào dự án của bạn, như mô-đun ES6, CommonJS và thậm chí <script>
trong HTML.
Nếu bạn có quyền truy cập vào máy chủ tên miền chéo và không muốn thực hiện bất kỳ thay đổi mã nào ở phía máy chủ, bạn có thể sử dụng thư viện có tên - 'xdomain'.
Làm thế nào nó hoạt động:
Bước 1: máy chủ 1: bao gồm thư viện xdomain và định cấu hình tên miền chéo làm nô lệ:
<script src="js/xdomain.min.js" slave="https://crossdomain_server/proxy.html"></script>
Bước 2: trên máy chủ tên miền chéo, tạo tệp proxy.html và bao gồm máy chủ 1 làm chủ:
proxy.html:
<!DOCTYPE HTML>
<script src="js/xdomain.min.js"></script>
<script>
xdomain.masters({
"https://server1" : '*'
});
</script>
Bước 3:
Bây giờ, bạn có thể thực hiện cuộc gọi AJAX đến proxy.html làm điểm cuối từ máy chủ1. Đây là bỏ qua yêu cầu CORS. Thư viện sử dụng nội bộ giải pháp iframe hoạt động với Thông tin xác thực và tất cả các phương thức có thể: GET, POST, v.v.
Truy vấn mã 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)