如何通过 JavaScript 发送跨域 POST 请求?
注意 - 它不应该刷新页面,之后我需要抓取并解析响应。
如何通过 JavaScript 发送跨域 POST 请求?
注意 - 它不应该刷新页面,之后我需要抓取并解析响应。
更新:在继续之前,每个人都应该阅读并理解关于 CORS的html5rocks 教程。它很容易理解并且非常清楚。
如果您控制正在发布的服务器,只需通过在服务器上设置响应标头来利用“跨源资源共享标准”。这个答案在这个线程的其他答案中讨论过,但在我看来不是很清楚。
简而言之,这里是如何完成从 from.com/1.html 到 to.com/postHere.php 的跨域 POST(以 PHP 为例)。注意:您只需要Access-Control-Allow-Origin
为非OPTIONS
请求设置- 本示例始终为较小的代码片段设置所有标头。
在 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。随着您继续阅读,这将变得清晰......
从 JS(jQuery 示例)设置您的跨域 POST:
$.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.');
}
});
当您在第 2 步中执行 POST 时,您的浏览器将向服务器发送一个“OPTIONS”方法。这是浏览器的“嗅探”,以查看服务器是否在您 POST 时很酷。如果请求源自“ http://from.com ”或“ https://from.com ” ,服务器会以“Access-Control-Allow-Origin”作为响应,告诉浏览器可以 POST|GET|ORIGIN 。由于服务器对它没问题,浏览器将发出第二个请求(这次是 POST)。让您的客户端设置它发送的内容类型是一种很好的做法 - 因此您也需要允许这样做。
MDN 有一篇关于HTTP 访问控制的精彩文章,详细介绍了整个流程的工作原理。根据他们的文档,它应该“在支持跨站点 XMLHttpRequest 的浏览器中工作”。然而,这有点误导,因为我认为只有现代浏览器才允许跨域 POST。我只在 safari、chrome、FF 3.6 上验证过这个。
如果您这样做,请记住以下几点:
如果您控制远程服务器,则可能应该使用 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();
您可能想要设置 iframe 的样式,使其隐藏并绝对定位。不确定浏览器是否允许跨站点发布,但如果是这样,这就是这样做的方法。
把事情简单化:
跨域POST:
使用crossDomain: true,
不应刷新页面:
不,它不会刷新页面,因为当服务器发回响应时将调用success
orerror
异步回调。
$.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
}
});
如果您有权访问所有涉及的服务器,请将以下内容放在其他域中请求的页面的回复标题中:
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;
}
这可能会产生安全问题,您应该确保采取适当的措施来验证请求。