使用跨源资源共享的跨域POST查询不会返回任何数据

我通过POST请求发送数据跨域但响应不起作用,具体而言,jQuery的成功处理程序永远不会被调用。

正在使用的东西:Django,Apache,jQuery。

所以,我设置了一个与此类似的请求:

$.ajax({ url: "http://somesite.com/someplace", type: "POST", cache: false, dataType: "json", data: { ... }, success: function( msg ) { alert(msg); }, }); 

众所周知, CORS允许我适当地回应OPTIONS查询,说“是的,你可以发给我”。 我在做什么 Firebug确认我收到了200状态代码,返回类型实际上是application/json 。 但是,Firebug还确认上面的成功处理程序没有被调用。

作为参考,我对OPTIONS回应是:

 elif request.method == "OPTIONS": response = HttpResponse("") response['Access-Control-Allow-Origin'] = "*" response['Access-Control-Allow-Methods'] = "POST, GET, OPTIONS" response['Access-Control-Allow-Headers'] = "X-Requested-With" return response 

相反,如果我设置了一个complete: function()...处理程序,它就可以了。

所以,问题是:发生了什么(或不发生)以及为什么? 我收到的数据很好,我只是希望能够返回响应。


更新这解决了我在某些浏览器上的问题,但由于我对此行为没有完全明确的解释,我将其保持打开状态

好的,所以我阅读了手册以及我对它的理解,所应用的算法大致如下:

  1. 用户代理可以实现预检调用。 这是OPTIONS请求。 他们的想法是,他们提出这个请求,让他们得到一个关于所请求资源的答案,然后他们应该缓存这些资源。 我没有传回一个max-age字段,所以我怀疑在返回成功并且X-request允许的情况下,用户代理的缓存中没有任何内容允许我创建它,因此默认规则(隔离请求) )应用。
  2. 当你提出实际请求时,我认为用户代理应该检查飞行前缓存的权限。 没有我的max-age字段,我相信它没有找到这些权限。 但是,在POST上使用相同的标题进行响应似乎允许Firefox和Google Chrome查看响应。 歌剧不能。 IE目前仍未经过测试。

我目前不理解,并且从手册(至少对我来说)中不清楚CORS请求是否也应该在请求和OPTIONS回答这些头。 我将尝试Max-Age标题,看看允许或不允许的内容。 但是,我仍然缺乏对这个问题的一些明确的权威性理解,所以如果有人在这里知道,我全都听见了。

好的,所以我相信正确的做事方式是这样的:

 if request.method == "POST": response = HttpResponse(simplejson.dumps(data),mimetype='application/json') response['Access-Control-Allow-Origin'] = "*" return response elif request.method == "OPTIONS": response = HttpResponse("") response['Access-Control-Allow-Origin'] = "*" response['Access-Control-Allow-Methods'] = "POST, OPTIONS" response['Access-Control-Allow-Headers'] = "X-Requested-With" response['Access-Control-Max-Age'] = "1800" else: return HttpResponseBadRequest() 

这是基于我根据预先请求从Mozilla挖出的文档 。

那么,我认为会发生的是:

  1. 如果预检高速缓存中没有任何内容, OPTIONS将通过X-Requested-With设置发送到XMLHttpRequest我相信这是允许Javascript访问任何内容以及Origin标头所必需的。
  2. 服务器可以检查该信息。 这是CORS的安全性 。 在我的情况下,我回答“任何来源都会做”和“你被允许发送X-Requested-With事情”。 我说OPTIONSPOST是允许的,并且这个响应应该被缓存30分钟。
  3. 然后客户端继续进行POST,之前正在运行。
  4. 我最初修改了响应包括Allow-MethodsAllow-Headers但是根据上面链接文档中的交换,这不是必需的。 这是有道理的,访问检查已经完成。
  5. 我相信那里发生的是这里描述的资源共享检查 。 基本上,一旦提出请求,浏览器就会再次检查Allow-Origin字段的有效性,这是在POST等请求上。 如果通过,客户端可以访问数据,如果没有,请求已经完成,但浏览器拒绝实际的客户端应用程序(Javascript)访问该数据。

我相信这是对正在发生的事情的正确总结,无论如何它似乎都有效。 如果我不对,请大声喊叫。

对于可能遇到此post的任何未来搜索者,以下资源是W3C 2008工作草案,深入讨论CORS。

http://www.w3.org/TR/2008/WD-access-control-20080912/

截至发布时,应该注意的是Chromium具体而且可能是所有WebKit都有一个错误,它会阻止Access-Control-Max-Age标头的值被尊重。 有关这方面的详细信息,请参阅Chromium Issue 131368的讨论页面。 总而言之 – 截至目前,基于WebKit的浏览器将以600 (10分钟)覆盖服务器返回的任何值作为值。

请求:

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

响应:

 response = HttpResponse(json.dumps('{"status" : "success"}')) response.__setitem__("Content-type", "application/json") response.__setitem__("Access-Control-Allow-Origin", "*") return response 

出于安全考虑,我不认为这是可能的。 唯一的跨域ajax调用哪些浏览器允许,可以使用JSONP完成,这些是专门的GET请求。

这将有效:

 $.ajax({ url: "http://somesite.com/someplace", type: "GET", cache: false, dataType: "JSONP", data: { ... }, success: function( msg ) { alert(msg); }, }); 

这不会:

 $.ajax({ url: "http://somesite.com/someplace", type: "POST", cache: false, dataType: "JSONP", data: { ... }, success: function( msg ) { alert(msg); }, });