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

时间:2011-03-09 20:22:27

标签: javascript jquery ajax cross-domain cors

我通过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()...处理程序,它就可以工作。

所以,问题是:发生了什么(或不发生)以及为什么?我的数据很好,我只想回复一下。


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

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

  1. 用户代理可以实施预检调用。这是OPTIONS请求。他们的想法是,他们提出这个请求,让他们得到一个关于所请求资源的答案,然后他们应该缓存这些资源。 我没有传回一个max-age 字段,所以我怀疑在返回成功并允许X-request时,用户代理的缓存中没有任何内容允许我创建它,所以应用默认规则(隔离请求)。
  2. 当您提出实际请求时,我认为用户代理应该检查飞行前缓存的权限。没有我的max-age字段,我相信它没有找到这些权限。但是,使用POST上的相同标头进行回复似乎允许Firefox和Google Chrome查看回复。歌剧不能。 IE目前仍未经过测试。
  3. 我目前不理解,并且从手册(至少对我来说)中不清楚CORS请求是否也应该回答请求中的这些标头以及OPTIONS。我将试验Max-Age标题并查看允许或不允许的内容。但是,我仍然缺乏对这个问题的一些明确的权威性理解,所以如果这里有人知道,我全都听见了。

4 个答案:

答案 0 :(得分:17)

好的,所以我认为正确的做事方式是:

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()

这是基于有关预检请求的documentation I dug up from Mozilla

所以,我相信会发生这样的事情:

  1. 如果预检缓存中没有任何内容,OPTIONS会在X-Requested-With设置为XMLHttpRequest的情况下发送,我相信这是允许Javascript访问任何内容以及Origin所必需的} header。
  2. 服务器可以检查该信息。 这是CORS的安全性。在我的情况下,我回答“任何来源都会做”和“你被允许发送X-Requested-With的东西”。我说OPTIONSPOST是允许的,并且此响应应缓存30分钟。
  3. 然后客户端继续进行POST,之前正在运行。
  4. 我最初修改了回复以包含Allow-MethodsAllow-Headers,但根据上述链接文档中的交换,这不是必需的。这是有道理的,访问检查已经完成。
  5. 我相信发生的事情是resource sharing check described here。基本上,一旦提出请求,浏览器就会再次检查Allow-Origin字段的有效性,这取决于POST等请求。如果通过,客户端可以访问数据,如果没有,请求已经完成,但浏览器拒绝实际的客户端应用程序(Javascript)访问该数据。
  6. 我相信这是对正在发生的事情的正确总结,无论如何它似乎都有效。如果我不对,请大喊。

答案 1 :(得分:1)

对于可能遇到此帖子的任何未来搜索者,以下资源是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分钟)覆盖服务器返回的值作为值。

答案 2 :(得分:0)

REQUEST:

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

答案 3 :(得分:-2)

出于安全考虑,我不认为这是可能的。浏览器允许的唯一跨域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);
    },
});