How do I send a cross-domain POST request via JavaScript?
如何通过JavaScript发送跨域POST请求?
注意 - 它不应该刷新页面,然后我需要抓取并解析响应。
更新:在继续之前,每个人都应该阅读并理解CORS上的html5rocks教程。这很容易理解,也很清楚。
如果您控制正在POST的服务器,只需通过在服务器上设置响应标头来利用"跨源资源共享标准"。这个答案将在本主题的其他答案中讨论,但在我看来并不是很清楚。
简而言之,您将如何完成从from.com/1.html到to.com/postHere.php的跨域POST(以PHP为例)。注意:您只需要为NON
在postHere.php中设置以下内容:
1 2 3 4 5 6 7 8 | 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设置跨域POST(jQuery示例):
1 2 3 4 5 6 7 8 9 10 11 12 13 | $.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"方法。这是浏览器的"嗅探",看看服务器是否很酷,你发布它。如果请求来自"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上进行了测试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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),则可以通过使用
- 炮眼
- XSSInterface
- EasyXDM
- jQuery PostMessage插件
如果您不控制远程服务器,则无法读取POST的响应时间段。否则会引起安全问题。
伪代码
1 2 3 4 5 6 7 8 9 10 11 | 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:
使用
不应刷新页面:
不,它不会刷新页面,因为当服务器发回响应时,将调用
示例脚本:
1 2 3 4 5 6 7 8 9 10 11 12 | $.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:
1 | header('Access-Control-Allow-Origin: *'); |
例如,在Drupal的xmlrpc.php代码中,您可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function xmlrpc_server_output($xml) { $xml = '<?xml version="1.0"?>'." ". $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(" ","", $xml); echo $xml; exit; } |
这可能会产生安全问题,您应该确保采取适当的措施来验证请求。
检查http://taiyolab.com/mbtweet/scripts/twitterapi_call.js中的
还有一点需要注意!
在上面的例子中,它描述了如何使用
1 2 3 4 5 6 | $.ajax({ type : 'POST', dataType : 'json', url : 'another-remote-server', ... }); |
JQuery 1.6及更低版本存在跨域XHR的错误。
据Firebug称,除了OPTIONS之外没有任何请求被发送。没有POST。完全没有。
花了5个小时测试/调整我的代码。在远程服务器(脚本)上添加大量标头。没有任何影响。
但后来,我将JQuery lib更新为1.6.4,一切都像魅力一样。
创建两个隐藏的iframe(将"display:none;"添加到css样式)。将您的第二个iframe指向您自己域中的内容。
创建一个隐藏的表单,将其方法设置为使用target =您的第一个iframe"发布",并可选择将enctype设置为"multipart / form-data"(我想你想要发送POST,因为你想发送多部分数据,比如图片?)
准备好后,将表单提交()POST。
如果您可以让其他域返回将使用Iframe进行跨域通信的JavaScript(http://softwareas.com/cross-domain-communication-with-iframes),那么您很幸运,并且您可以捕获响应同样。
当然,如果您想将服务器用作代理,则可以避免所有这些。只需将表单提交给您自己的服务器,该服务器将请求代理到其他服务器(假设其他服务器未设置为通知IP差异),获取响应并返回您喜欢的任何内容。
如果您想在使用JQuery AJAX的ASP.net MVC环境中执行此操作,请按照下列步骤操作:
(这是此线程提供的解决方案的摘要)
假设"caller.com"(可以是任何网站)需要发布到"server.com"(ASP.net MVC应用程序)
在"server.com"应用程序的Web.config上添加以下部分:
1 2 3 4 5 6 7 | <httpProtocol> <customHeaders> </customHeaders> </httpProtocol> |
在"server.com"上,我们将在我们将要发布的控制器(称为"Home")上执行以下操作:
1 2 3 4 5 6 7 8 9 10 11 | [HttpPost] public JsonResult Save() { //Handle the post data... return Json( new { IsSuccess = true }); } |
然后从"caller.com",将表格中的数据(使用html id"formId")发布到"server.com",如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $.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。
发送者邮箱上的父母
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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"); |
在reciver.com上的iframe
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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(例如jQuery中的$ .ajax(),$ .post())和一个跨源资源共享polyfills https://github.com/Modernizr/Modernizr/wiki/HTML5-跨浏览器Polyfills#维基-CORS
我知道这是一个老问题,但我想分享我的方法。我使用cURL作为代理,非常简单和一致。创建一个名为submit.php的php页面,并添加以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <? 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):
1 2 3 4 5 6 7 8 9 10 11 12 13 | $.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.'); } }); |
这是一个老问题,但一些新技术可能会帮助某人。
如果您具有对其他服务器的管理访问权限,则可以使用opensource Forge项目来完成跨域POST。 Forge提供了一个跨域JavaScript XmlHttpRequest包装器,它利用了Flash的原始套接字API。 POST甚至可以通过TLS完成。
您需要对要发布的服务器进行管理访问的原因是您必须提供允许从您的域进行访问的跨域策略。
http://github.com/digitalbazaar/forge
如果您可以访问跨域服务器并且不希望在服务器端进行任何代码更改,则可以使用名为"xdomain"的库。
这个怎么运作:
步骤1:
server 1:包含xdomain库并将跨域配置为slave:
1 | <script src="js/xdomain.min.js" slave="https://crossdomain_server/proxy.html"> |
第2步:
在跨域服务器上,创建proxy.html文件并将服务器1包含为主服务器:
1 2 3 4 5 6 7 | proxy.html: <!DOCTYPE HTML> <script src="js/xdomain.min.js"> xdomain.masters({ "https://server1" : '*' }); |
第3步:
现在,您可以从server1对proxy.html进行AJAX调用作为端点。这绕过了CORS请求。该库内部使用iframe解决方案,该解决方案与Credentials和所有可能的方法一起使用:GET,POST等。
查询ajax代码:
1 2 3 4 5 6 7 8 9 | $.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) |
CORS适合你。
CORS是"跨域资源共享",是一种发送跨域请求的方式。现在XMLHttpRequest2和Fetch API都支持CORS,它可以发送POST和GET请求
但它有其限制.Server需要特定声明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.It没有依赖性,更少超过3KB,它支持Fetch,AJAX和JSONP具有相同的致命样本语法和选项。
1 2 3 | catta('./data/simple.json').then(function (res) { console.log(res); }); |
它还支持导入项目的所有方式,如ES6模块,CommonJS甚至HTML中的
应该可以使用YQL自定义表+ JS XHR,看看:
http://developer.yahoo.com/yql/guide/index.html
我用它来做一些客户端(js)html抓取,工作正常
(我有一个完整的音频播放器,搜索互联网/播放列表/歌词/最后的fm信息,所有客户端js + YQL)