How to get a cross-origin resource sharing (CORS) post request working
我的局域网上有一台机器,它有两个Web服务器。第一个是在XBMC(端口8080)中内置的一个,并显示我们的库。第二个服务器是一个ChelypyyPython脚本(端口8081),我用它来触发一个按需的文件转换。文件转换是由来自XBMC服务器的页面的Ajax POST请求触发的。
- Goto http://MeMeCe: 8080显示库
- 显示库
- 用户单击"convert"链接,发出以下命令-
jquery-ajax请求
1 | $.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)}) |
- 浏览器发出一个HTTP选项请求,其标题如下:
请求头-选项
1 2 3 4 5 6 7 8 9 10 11 | Host: machineA:8081 User-Agent: ... Firefox/4.01 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 115 Connection: keep-alive Origin: http://machineA:8080 Access-Control-Request-Method: POST Access-Control-Request-Headers: x-requested-with |
- 服务器响应如下:
响应头-选项(状态=200 OK)
1 2 3 4 5 6 7 8 | Content-Length: 0 Access-Control-Allow-Headers: * Access-Control-Max-Age: 1728000 Server: CherryPy/3.2.0 Date: Thu, 21 Apr 2011 22:40:29 GMT Access-Control-Allow-Origin: * Access-Control-Allow-Methods: POST, GET, OPTIONS Content-Type: text/html;charset=ISO-8859-1 |
- 然后对话停止。从理论上讲,当服务器以正确的(?)响应时,浏览器应该发出一个POST请求。CORS头文件(访问控制允许源文件:*)
为了进行故障排除,我还从http://jquery.com发出了相同的$.post命令。这就是我遇到困难的地方,从jquery.com,post请求起作用,然后通过post发送选项请求。此事务的标题如下:
请求头-选项
1 2 3 4 5 6 7 8 9 10 | Host: machineA:8081 User-Agent: ... Firefox/4.01 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 115 Connection: keep-alive Origin: http://jquery.com Access-Control-Request-Method: POST |
响应头-选项(状态=200 OK)
1 2 3 4 5 6 7 8 | Content-Length: 0 Access-Control-Allow-Headers: * Access-Control-Max-Age: 1728000 Server: CherryPy/3.2.0 Date: Thu, 21 Apr 2011 22:37:59 GMT Access-Control-Allow-Origin: * Access-Control-Allow-Methods: POST, GET, OPTIONS Content-Type: text/html;charset=ISO-8859-1 |
请求头-发布
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Host: machineA:8081 User-Agent: ... Firefox/4.01 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 115 Connection: keep-alive Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Referer: http://jquery.com/ Content-Length: 12 Origin: http://jquery.com Pragma: no-cache Cache-Control: no-cache |
响应头-日志(状态=200 OK)
1 2 3 4 5 6 7 8 | Content-Length: 32 Access-Control-Allow-Headers: * Access-Control-Max-Age: 1728000 Server: CherryPy/3.2.0 Date: Thu, 21 Apr 2011 22:37:59 GMT Access-Control-Allow-Origin: * Access-Control-Allow-Methods: POST, GET, OPTIONS Content-Type: application/json |
我不明白为什么同一个请求在一个站点上有效,而在另一个站点上无效。我希望有人能指出我遗漏了什么。谢谢你的帮助!
我终于偶然发现了这个链接:"CORS POST请求是从普通JavaScript中工作的,但是为什么不使用jQuery呢?"注意到jQuery 1.5.1增加了
1 | Access-Control-Request-Headers: x-requested-with |
头向所有CORS请求。jQuery 1.5.2不这样做。同样,根据同一个问题,设置服务器响应头
1 | Access-Control-Allow-Headers: * |
不允许响应继续。您需要确保响应头具体包含所需的报头。IE:
1 | Access-Control-Allow-Headers: x-requested-with |
请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $.ajax({ url:"http://localhost:8079/students/add/", type:"POST", crossDomain: true, data: JSON.stringify(somejson), dataType:"json", success: function (response) { var resp = JSON.parse(response) alert(resp.status); }, error: function (xhr, status) { alert("error"); } }); |
回应:
1 2 3 4 5 | response = HttpResponse(json.dumps('{"status" :"success"}')) response.__setitem__("Content-type","application/json") response.__setitem__("Access-Control-Allow-Origin","*") return response |
我花了点时间才找到解决办法。
如果您的服务器响应正确,并且请求有问题,您应该在请求中添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $.ajax({ url: url, type: method, // This is the important part xhrFields: { withCredentials: true }, // This is the important part data: data, success: function (response) { // handle the response }, error: function (xhr, status) { // handle errors } }); |
Note: jQuery >= 1.5.1 is required
我在这个问题上挣扎了几个星期。
要做到这一点,最简单、最兼容和非黑客的方法可能是使用一个提供程序JavaScriptAPI,它不进行基于浏览器的调用,并且可以处理跨源请求。
例如facebook javascript api和google js api。
如果您的API提供程序不是最新的,并且在其响应中不支持跨源资源源'*'头,并且没有JSAPI(是的,我是在说您Yahoo),您会被三个选项中的一个击中。-
在请求中使用JSONP,这会向URL添加一个回调函数,您可以在其中处理响应。警告:这将更改请求的URL,因此您的API服务器必须具备处理?callback=在URL的末尾。
将请求发送到您的API服务器,该服务器是您的控制器,与客户端位于同一域中,或者启用了跨源资源共享,从中可以将请求代理到第三方API服务器。
在您发出OAuth请求并需要处理用户交互的情况下,可能最有用,哈哈!
我用jqueryajax设置了我的请求头,解决了我在使用谷歌距离矩阵API时遇到的问题。看看下面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var settings = { 'cache': false, 'dataType':"jsonp", "async": true, "crossDomain": true, "url":"https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=place_id:"+me.originPlaceId+"&destinations=place_id:"+me.destinationPlaceId+"®ion=ng&units=metric&key=mykey", "method":"GET", "headers": { "accept":"application/json", "Access-Control-Allow-Origin":"*" } } $.ajax(settings).done(function (response) { console.log(response); }); |
注意我在设置中添加的内容**
1 2 3 4 | "headers": { "accept":"application/json", "Access-Control-Allow-Origin":"*" } |
**我希望这有帮助。
把这个和拉拉维尔结合起来解决了我的问题。只需将这个头添加到jquery请求
我有一个完全相同的问题,jQueryAjax只给了我关于POST请求的CORS问题,GET请求工作得很好——我厌倦了上面的所有工作,没有结果。我的服务器等中有正确的头文件。转换为使用xmlhttprequest而不是jquery立即解决了我的问题。不管我使用哪个版本的jquery,它都没有修复它。如果不需要向后的浏览器兼容性,FETCH也不会有问题。
1 2 3 4 5 6 7 8 | var xhr = new XMLHttpRequest() xhr.open('POST', 'https://mywebsite.com', true) xhr.withCredentials = true xhr.onreadystatechange = function() { if (xhr.readyState === 2) {// do something} } xhr.setRequestHeader('Content-Type', 'application/json') xhr.send(json) |
希望这有助于解决同样问题的其他人。
出于某种原因,关于GET请求的问题已与此问题合并,因此我将在此处对此作出响应。
这个简单的函数将从启用CORS的页面异步获取HTTP状态回复。如果您运行它,您将看到只有具有适当头的页面在通过xmlhttprequest访问时返回200状态——无论使用GET还是POST。除了可能使用JSONP(如果您只需要一个JSON对象)之外,在客户机端什么也做不到。
可以轻松修改以下内容,以获取保存在xmlhttpRequestObject对象中的数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function checkCorsSource(source) { var xmlHttpRequestObject; if (window.XMLHttpRequest) { xmlHttpRequestObject = new XMLHttpRequest(); if (xmlHttpRequestObject != null) { var sUrl =""; if (source =="google") { var sUrl ="https://www.google.com"; } else { var sUrl ="https://httpbin.org/get"; } document.getElementById("txt1").innerHTML ="Request Sent..."; xmlHttpRequestObject.open("GET", sUrl, true); xmlHttpRequestObject.onreadystatechange = function() { if (xmlHttpRequestObject.readyState == 4 && xmlHttpRequestObject.status == 200) { document.getElementById("txt1").innerHTML ="200 Response received!"; } else { document.getElementById("txt1").innerHTML ="200 Response failed!"; } } xmlHttpRequestObject.send(); } else { window.alert("Error creating XmlHttpRequest object. Client is not CORS enabled"); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <html> <head> Check if page is cors </head> <body> <p> A CORS-enabled source has one of the following HTTP headers: </p> <ul> <li> Access-Control-Allow-Headers: * </li> <li> Access-Control-Allow-Headers: x-requested-with </li> </ul> <p> Click a button to see if the page allows CORS </p> <form name="form1" action="" method="get"> <input type="button" name="btn1" value="Check Google Page" onClick="checkCorsSource('google')"> <input type="button" name="btn1" value="Check Cors Page" onClick="checkCorsSource('cors')"> </form> <p id="txt1" /> </body> </html> |
如果由于某些原因,在尝试添加头文件或设置控制策略时,仍然没有找到可以考虑使用ApacheProxyPass的地方…
例如,在一个使用ssl的
1 2 | SSLProxyEngine On ProxyPass /oauth https://remote.tld/oauth |
确保已加载以下Apache模块(使用a2enmod加载它们):
- 代理
- 脯氨酸连接
- PROXY-HTTP
显然,为了使用Apache代理,您必须更改Ajax请求的URL…
以下是我的工作总结:
定义新函数(包装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | jQuery.postCORS = function(url, data, func) { if(func == undefined) func = function(){}; return $.ajax({ type: 'POST', url: url, data: data, dataType: 'json', contentType: 'application/x-www-form-urlencoded', xhrFields: { withCredentials: true }, success: function(res) { func(res) }, error: function() { func({}) } }); } |
用途:
1 2 3 4 5 | $.postCORS("https://example.com/service.json",{ x : 1 },function(obj){ if(obj.ok) { ... } }); |
还与
1 2 3 4 5 6 7 | $.postCORS("https://example.com/service.json",{ x : 1 }).done(function(obj){ if(obj.ok) { ... } }).fail(function(){ alert("Error!"); }); |
服务器端(本例中是example.com的宿主),设置这些头(在php中添加了一些示例代码):
1 2 3 4 5 6 | header('Access-Control-Allow-Origin: https://not-example.com'); header('Access-Control-Allow-Credentials: true'); header('Access-Control-Max-Age: 604800'); header("Content-type: application/json"); $array = array("ok" => $_POST["x"]); echo json_encode($array); |
这是我知道的唯一真正从JS跨域发布的方法。
jsonp将post转换为get,get可以在服务器日志中显示敏感信息。
这次聚会有点晚了,但我已经为此挣扎了几天了。这是可能的,我在这里找到的答案都没有奏效。这看起来很简单。以下是.ajax调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <!DOCTYPE HTML> <html> <head> <body> Javascript Test <script src="http://code.jquery.com/jquery-latest.min.js"> <script type="text/javascript"> $(document).domain = 'XXX.com'; $(document).ready(function () { $.ajax({ xhrFields: {cors: false}, type:"GET", url:"http://XXXX.com/test.php?email='[email protected]'", success: function (data) { alert(data); }, error: function (x, y, z) { alert(x.responseText +" :EEE:" + x.status); } }); }); </body> </html> |
下面是服务器端的PHP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <html> <head> PHP Test </head> <body> <?php header('Origin: xxx.com'); header('Access-Control-Allow-Origin:*'); $servername ="sqlxxx"; $username ="xxxx"; $password ="sss"; $conn = new mysqli($servername, $username, $password); if ($conn->connect_error) { die("Connection failed:" . $conn->connect_error); } $sql ="SELECT email, status, userdata FROM msi.usersLive"; $result = $conn->query($sql); if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) { echo $row["email"] .":" . $row["status"] .":" . $row["userdata"] . ""; } } else { echo"{ }"; } $conn->close(); ?> </body> |