如何通过JavaScript发送跨域POST请求?
如何通过JavaScript发送跨域POST请求?
注意 – 它不应该刷新页面,我需要抓住并parsing响应。
一些代码示例的帮助将非常感谢。
更新:在继续之前,每个人都应该阅读和理解CORS上的html5rocks教程 。 这很容易理解,非常清楚。
如果您控制正在发布的服务器,只需在服务器上设置响应标题即可使用“跨源资源共享标准”。 这个答案在这个线程的其他答案中讨论,但在我看来不是很清楚。
简而言之,就是如何完成从from.com/1.html到to.com/postHere.php的跨域POST(以PHP为例)。 注意:您只需要OPTIONS
请求请求设置Access-Control-Allow-Origin
,本例总是为所有较小的代码片段设置标题。
-
在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”方法。 这是浏览器的“嗅探”,以查看服务器在发布之后是否很酷。 如果请求源自“ http://from.com ”或“ https://from.com ”,则服务器响应“访问控制 – 允许 – 来源”告诉浏览器可以发送POST | GET | ORIGIN。 由于服务器可以,浏览器会发出第二个请求(这次是POST)。 让客户端设置它正在发送的内容types是一个很好的做法 – 所以你也需要允许。
MDN对HTTP访问控制进行了很好的介绍,详细介绍了整个stream程的工作原理。 根据他们的文档,它应该“在支持跨站点XMLHttpRequest的浏览器中工作”。 不过,这有点让人误解,因为我认为只有现代浏览器允许跨域POST。 我只validation了这个与safari,铬,FF 3.6的作品。
请记住以下内容,如果你这样做:
- 您的服务器将不得不处理每个操作2个请求
- 你将不得不考虑安全性的影响。 在做“Access-Control-Allow-Origin:*”之前要小心
- 这不会在移动浏览器上工作。 根据我的经验,他们根本不允许跨域POST。 我testing过Android,iPad,iPhone
- 在FF <3.6中有一个非常大的错误,如果服务器返回一个非400响应代码并且有一个响应主体(例如validation错误),那么FF 3.6不会得到响应主体。 这是一个巨大的痛苦,因为你不能使用良好的REST实践。 看到这里的错误(它在jQuery下的提交,但我的猜测是它的FF错误 – 似乎在FF4中修复)。
- 总是返回上面的标题,而不仅仅是OPTION请求。 FF在POST的响应中需要它。
如果您控制远程服务器,则应该使用CORS,如本答案中所述 ; 它支持IE8及以上版本,以及FF,GC和Safari的所有最新版本。 (但在IE8和9中,CORS将不允许您在请求中发送Cookie。)
所以,如果你不控制远程服务器,或者你必须支持IE7,或者如果你需要cookies,并且你必须支持IE8 / 9,你可能需要使用iframe技术。
- 创build一个唯一名称的iframe。 (iframe对整个浏览器使用全局名称空间,所以select一个不会被其他网站使用的名称。)
- 构build一个带有隐藏input的表单,以iframe为目标。
- 提交表单。
这里是示例代码; 我在IE6,IE7,IE8,IE9,FF4,GC11,S5上testing过。
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
和/或许多库中的一个允许您在旧版浏览器中发送跨域的跨框架消息:
- 炮眼
- XSSInterface
- EasyXDM
- jQuery的PostMessage插件
如果您不控制远程服务器,则无法读取POST的响应时间段。 否则会导致安全问题。
- 创build一个iFrame,
- 用隐藏的input来放置一个表单,
- 将表单的操作设置为URL,
- 将iframe添加到文档
- 提交表格
伪代码
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的样式,以隐藏并绝对定位。 不确定浏览器允许跨网站发帖,但如果是这样的话,这是怎么做的。
如果您有权访问涉及的所有服务器,请在其他域中请求的页面的回复标题中input以下内容:
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; }
这可能会造成安全问题,您应该确保采取适当的措施来validation请求。
把事情简单化:
-
跨域POST:
使用crossDomain: true,
-
不应刷新页面:
不,它不会刷新页面,因为当服务器发回响应时,会调用success
或error
asynchronouscallback。
示例脚本:
$.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 } });
检查http://taiyolab.com/mbtweet/scripts/twitterapi_call.js中的;post_method
函数 – 上述iframe方法的一个很好的例子。
-
创build两个隐藏的iframe(将“display:none;”添加到CSS样式)。 让你的第二个iframe指向你自己的领域的东西。
-
创build一个隐藏的窗体,将其方法设置为“发布”与目标=您的第一个iframe,并可选地设置enctype为“multipart / form-data”(我想你想要做POST,因为你想发送像图片的多部分数据?)
-
准备好后,将表单提交()POST。
-
如果你可以得到另一个域返回的JavaScript,将跨域与iframes( http://softwareas.com/cross-domain-communication-with-iframes )通信,那么你很幸运,你可以捕获响应以及。
当然,如果你想用你的服务器作为代理,你可以避免这一切。 只需将表单提交给您自己的服务器,该服务器会将请求代理给其他服务器(假设其他服务器未设置为注意到IP差异),获取响应并返回您喜欢的任何内容。
一个更重要的事情要注意! 在上面的例子中描述了如何使用
$.ajax({ type : 'POST', dataType : 'json', url : 'another-remote-server', ... });
JQuery 1.6及更低版本有一个跨域XHR的错误。 根据Firebug没有请求,除了OPTIONS被发送。 没有POST。 完全一样。
花了5个小时testing/调整我的代码。 在远程服务器上添加很多标题(脚本)。 没有任何影响。 但后来,我已经更新了JQuery库到1.6.4,一切都像一个魅力。
如果你想在使用JQuery AJAX的ASP.net MVC环境中执行此操作,请按照下列步骤操作:(这是本主题提供的解决scheme的摘要)
假设“caller.com”(可以是任何网站)需要发布到“server.com”(一个ASP.net MVC应用程序)
-
在“server.com”应用程序的Web.config中添加以下部分:
<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”上,我们将在控制器(称为“主页”)上发布以下操作:
[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 } });
高级别….您需要在您的服务器上设置一个cname,以使other-serve.your-server.com指向other-server.com。
你的页面dynamic创build一个不可见的iframe,它充当你的传输到other-server.com。 然后,您必须通过JS从您的页面与other-server.com进行通信,并通过回叫将数据返回到您的页面。
可能的,但需要your-server.com和other-server.com的协调
这是一个古老的问题,但是一些新技术可能会帮助别人。
如果您有其他服务器的pipe理访问权限,那么您可以使用opensource Forge项目来完成跨域POST。 Forge提供了一个跨域JavaScript XmlHttpRequest包装器,它利用了Flash的原始套接字API。 POST甚至可以通过TLS完成。
您需要对您发布的服务器进行pipe理访问的原因是您必须提供允许从您的域进行访问的跨域策略。
我认为最好的方法是使用XMLHttpRequest(例如jQuery中的$ .ajax(),$ .post())和一个跨源资源共享polyfill https://github.com/Modernizr/Modernizr/wiki/HTML5-跨浏览器Polyfills#维基-CORS
还有一种方法(使用html5function)。 您可以使用托pipe在其他域上的代理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");
在reciver.com上的iframe
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) }
应该可以用YQL自定义表+ JS XHR,看看: http : //developer.yahoo.com/yql/guide/index.html
我用它来做一些客户端(JS)的HTML抓取,工作正常(我有一个完整的audio播放器,search互联网/播放列表/歌词/最后FM信息,所有客户端JS + YQL)
我知道这是一个古老的问题,但我想分享我的方法。 我使用cURL作为代理,非常简单和一致。 创build一个名为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.'); } });
CORS是给你的。 CORS是“跨源资源共享”,是发送跨域请求的一种方式。现在XMLHttpRequest2和Fetch API都支持CORS,它可以同时发送POST和GET请求
但它有其局限性。服务器需要具体声明Access-Control-Allow-Origin ,并且不能设置为'*'。
如果你想要任何来源可以向你发送请求,你需要JSONP(也需要设置访问控制允许来源 ,但可以是'*')
如果你不知道如何select,那么对于很多的请求方式,我想你需要一个完整的function组件来做到这一点。让我来介绍一个简单的组件https://github.com/Joker-Jelly/catta
如果您使用的是现代浏览器(> IE9,Chrome,FF,Edge等),build议您使用简单但美观的组件https://github.com/Joker-Jelly/catta。;它没有依赖性,比3KB,它支持Fetch,AJAX和JSONP具有相同的致命的示例语法和选项。
catta('./data/simple.json').then(function (res) { console.log(res); });
它也支持一路导入到你的项目中,比如ES6模块,CommonJS甚至HTML中的<script>
。