如何通过JavaScript发送跨域POST请求?

如何通过JavaScript发送跨域POST请求?

注释-它不应该刷新页面,然后我需要抓取并解析响应。

580336 次浏览
  1. 创建一个iFrame,
  2. 在里面放入一个隐藏输入的表单,
  3. 将表单的动作设置为URL,
  4. 向文档中添加iframe
  5. 提交表格

伪代码

 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,隐藏和绝对定位。不确定跨站点发布将被浏览器允许,但如果是这样,这是如何做到的。

高水平……您需要在服务器上设置cname,以便other-ser.your-server.com指向other-server.com。

您的页面动态地创建了一个不可见的iframe,它充当您到other-server.com的传输。然后,您必须通过JS从您的页面与other-server.com通信,并使用回调将数据返回到您的页面。

可能,但需要your-server.com和other-server.com的协调

检查http://taiyolab.com/mbtweet/scripts/twitterapi_call.js中的post_method函数——上面描述的iframe方法的一个很好的例子。

  1. 创建两个隐藏的iframe(在css样式中添加"display: none;")。让你的第二个iframe指向你自己域中的某个东西。

  2. 创建一个隐藏表单,将其方法设置为“post”,target =你的第一个iframe,并可选地设置enctype为“multipart/form-data”(我认为你想做post是因为你想发送多部分数据,如图片?)

  3. 准备就绪时,使表单提交()POST。

  4. 如果你能让其他域返回javascript,将与Iframes进行跨域通信(http://softwareas.com/cross-domain-communication-with-iframes),那么你很幸运,你也可以捕获响应。

当然,如果您想使用您的服务器作为代理,您可以避免所有这些。只需将表单提交到您自己的服务器,该服务器将把请求代理到另一个服务器(假设另一个服务器没有设置为注意到IP差异),获得响应,并返回您想要的任何内容。

应该可以与YQL自定义表+ JS XHR,看看: # EYZ0 < / p >

我用它来做一些客户端(js) html抓取,工作很好 (我有一个完整的音频播放器,搜索互联网/播放列表/歌词/最后的fm信息,所有客户端js + YQL)

这是一个老问题,但一些新技术可能会帮助人们解决这个问题。

如果你有对其他服务器的管理访问权限,那么你可以使用开源Forge项目来完成你的跨域POST。Forge提供了一个跨域JavaScript XmlHttpRequest包装器,它利用了Flash的原始套接字API。POST甚至可以通过TLS完成。

您需要对您要发布的服务器进行管理访问的原因是,您必须提供一个跨域策略,允许从您的域进行访问。

http://github.com/digitalbazaar/forge

如果您可以访问所有相关的服务器,请在另一个域请求的页面的回复标题中放入以下内容:

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;
}

这可能会产生安全问题,您应该确保采取了适当的措施来验证请求。

如果你控制远程服务器,你可能应该使用CORS,就像答案中描述的那样;它在IE8及以上版本,以及FF、GC和Safari的所有最新版本中都得到支持。(但是在IE8和ie9中,CORS不允许你在请求中发送cookie。)

所以,如果你控制远程服务器,或者如果你必须支持IE7,或者如果你需要cookie并且你必须支持IE8/9,你可能会想要使用iframe技术。

  1. 创建一个名称唯一的iframe。(iframes为整个浏览器使用全局名称空间,因此请选择其他网站不会使用的名称。)
  2. 构造一个带有隐藏输入的表单,以iframe为目标。
  3. 提交表单。

下面是示例代码;我在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的响应,句号。否则会导致安全问题。

在继续之前,每个人都应该阅读和理解CORS上的html5rocks教程。它很容易理解,也很清楚。

如果您控制被post的服务器,只需通过在服务器上设置响应头来利用“跨源资源共享标准”。这个答案在本帖的其他答案中讨论过,但在我看来不是很清楚。

简而言之,下面是如何完成从from.com/1.html到to.com/postHere.php的跨域POST(以PHP为例)。注意:你只需要为非OPTIONS请求设置Access-Control-Allow-Origin -这个例子总是为一个较小的代码片段设置所有的头。

  1. 在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。

  2. 设置你的跨域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.');
    }
    });
    

When you do the POST in step 2, your browser will send a "OPTIONS" method to the server. This is a "sniff" by the browser to see if the server is cool with you POSTing to it. The server responds with an "Access-Control-Allow-Origin" telling the browser its OK to POST|GET|ORIGIN if request originated from "http://from.com" or "https://from.com". Since the server is OK with it, the browser will make a 2nd request (this time a POST). It is good practice to have your client set the content type it is sending - so you'll need to allow that as well.

MDN has a great write-up about HTTP access control, that goes into detail of how the entire flow works. According to their docs, it should "work in browsers that support cross-site XMLHttpRequest". This is a bit misleading however, as I THINK only modern browsers allow cross domain POST. I have only verified this works with safari,chrome,FF 3.6.

Keep in mind the following if you do this:

  1. Your server will have to handle 2 requests per operation
  2. You will have to think about the security implications. Be careful before doing something like 'Access-Control-Allow-Origin: *'
  3. This wont work on mobile browsers. In my experience they do not allow cross domain POST at all. I've tested android, iPad, iPhone
  4. There is a pretty big bug in FF < 3.6 where if the server returns a non 400 response code AND there is a response body (validation errors for example), FF 3.6 wont get the response body. This is a huge pain in the ass, since you cant use good REST practices. See bug here (its filed under jQuery, but my guess is its a FF bug - seems to be fixed in FF4).
  5. Always return the headers above, not just on OPTION requests. FF needs it in the response from the POST.

我认为最好的方法是使用XMLHttpRequest(例如jQuery中的$.ajax(), $.post())与跨起源资源共享polyfills https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills#wiki-CORS之一

还有一件重要的事要注意!! 在上面的例子中描述了如何使用

$.ajax({
type     : 'POST',
dataType : 'json',
url      : 'another-remote-server',
...
});
JQuery 1.6及以下版本有跨域XHR的bug。 根据Firebug,除了OPTIONS之外,没有其他请求发送。没有职位。。< / p > 花了5个小时测试/调优我的代码。在远程服务器(脚本)上添加大量的头文件。没有任何效果。 但是后来,我把JQuery lib更新到1.6.4,一切都像一个魅力

我知道这是一个老问题,但我想分享我的方法。我使用cURL作为代理,非常简单和一致。创建一个名为submit.php的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.');
}
});
如果你想在ASP.net MVC环境下使用JQuery AJAX实现这个功能,请遵循以下步骤: (这是在线程提供的解决方案的摘要)

假设"caller.com"(可以是任何网站)需要发布到"server.com"(一个ASP.net MVC应用程序)

  1. 在“server.com”应用程序的Web。配置添加如下部分:

      <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>
    
  2. On the "server.com", we'll have the following action on the controller(called "Home") to which we will be posting:

    [HttpPost]
    public JsonResult Save()
    {
    //Handle the post data...
    
    
    return Json(
    new
    {
    IsSuccess = true
    });
    }
    
  3. Then from the "caller.com", post data from a form(with the html id "formId") to "server.com" as follow:

    $.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)
}

保持简单:

    <李> < p > # EYZ0 < br > 使用# EYZ0 < / p > <李> < p > # EYZ0 < br > 不,它不会刷新页面,因为当服务器发送回响应时将调用successerror异步回调

示例脚本:

$.ajax({
type: "POST",
url: "http://www.yoururl.com/",
crossDomain: true,
data: 'param1=value1&param2=value2',
success: function (data) {
// do something with server response data
},
error: function (err) {
// handle your error logic here
}
});
CORS是为你准备的。 CORS是“跨域资源共享”,是一种发送跨域请求的方式。现在XMLHttpRequest2和Fetch 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。它没有依赖性,小于3KB,它支持Fetch, AJAX和JSONP,具有相同的致命示例语法和选项。

catta('./data/simple.json').then(function (res) {
console.log(res);
});

它还支持所有方式导入到您的项目,如ES6模块,CommonJS,甚至HTML中的<script>

如果你可以访问跨域服务器,并且不想在服务器端做任何代码更改,你可以使用一个名为“xdomain”的库。

工作原理:

< p >步骤1: 服务器1:包含xdomain库并将跨域配置为从域:

<script src="js/xdomain.min.js" slave="https://crossdomain_server/proxy.html"></script>
< p >步骤2: 在跨域服务器上,创建一个proxy.html文件,并包括服务器1作为主服务器:

proxy.html:
<!DOCTYPE HTML>
<script src="js/xdomain.min.js"></script>
<script>
xdomain.masters({
"https://server1" : '*'
});
</script>

步骤3:

现在,您可以从server1对proxy.html作为端点进行AJAX调用。这是绕过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)