【问题标题】:Cross domain POST query using Cross-Origin Resource Sharing getting no data back使用跨域资源共享的跨域 POST 查询没有返回数据
【发布时间】:2011-07-12 05:20:22
【问题描述】:

我正在通过 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 请求时,用户代理的缓存中没有任何内容允许我这样做,所以应用默认规则(隔离请求)。
  2. 当您发出实际请求时,我相信用户代理应该检查飞行前缓存的权限。如果没有我的 max-age 字段,我相信它找不到这些权限。但是,在 POST 上使用相同的标题进行响应似乎允许 Firefox 和 Google Chrome 查看响应。歌剧不能。 IE 目前尚未经过测试。

我目前不明白,从手册中也不清楚(至少对我而言)CORS 请求是否也应该在请求中使用这些标头以及OPTIONS 来回答。我将试验Max-Age 标头,看看允许或不允许什么。但是,我对这个问题仍然缺乏一定的权威理解,所以如果这里有人知道,我会全力以赴。

【问题讨论】:

  • 可能由于是跨域调用而受到限制。我不想登录 mybank.com 并将我的信息发送到 somebank.com(同样的前提适用于此处,无论有效负载多么微不足道)。
  • 信息已发送。 CORS 实现了这一点。因此,任何应该受到保护的信息都刚刚发布到一个完全独立的域,现在位于我的 Postgres 服务器中。太晚了。这里的问题不是发送信息,而是接收信息。
  • 浏览器不支持这个。数据已收到,但浏览器不让你看到。您可以使用“fiddler”进行测试
  • @Ninefingers:我以发送为例,但问题仍然与跨域相关。如果我太含糊,我很抱歉。
  • 不确定,但可能是您需要使用 jsonp 而不是 json。 codeproject.com/KB/aspnet/JSONToJSONP.aspx

标签: javascript jquery ajax cross-domain cors


【解决方案1】:

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

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 标头所必需的。
  2. 服务器可以检查该信息。 这就是 CORS 的安全性。就我而言,我的回应是“任何来源都可以”和“你可以发送X-Requested-With 的东西”。我是说OPTIONSPOST 是允许的,并且这个响应应该被缓存30 分钟。
  3. 然后客户端继续执行 POST,这在之前是有效的。
  4. 我修改了最初的响应以包含Allow-MethodsAllow-Headers,但根据上述链接文档中的交换,这不是必需的。这是有道理的,访问检查已经完成。
  5. 我相信发生的事情是resource sharing check described here。基本上,一旦发出了所述请求,浏览器就会再次检查Allow-Origin 字段的有效性,这在诸如POST 之类的请求上。如果通过,客户端可以访问数据,如果没有,则请求已经完成,但浏览器拒绝实际的客户端应用程序 (Javascript) 访问该数据。

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

【讨论】:

  • 您确定Access-Control-Allow-Origin: "*" 是来自服务器的合法响应吗?我的理解是服务器可以接受任何来源,但它应该使用客户端的 Origin 标头响应每个请求...
  • 它是有效的,是的 - 但请注意,如果您传递 xhr 凭据,无论如何,通配符来源接受都将失败。
  • Access-Control-Max-Age: 180 = 3 分钟,而不是 30 分钟。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    请求:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • -1 因为“浏览器允许的唯一跨域 ajax 调用可以使用 JSONP 完成”不正确。我已经管理了一个跨域 ajax 调用,或者其中的一半,当我说“不取回数据”时很明显。我很清楚 JSONP 机制;我对我在这里使用的 CORS (en.wikipedia.org/wiki/Cross-Origin_Resource_Sharing) 的来龙去脉不够熟悉。
      猜你喜欢
      • 2018-05-04
      • 2011-05-07
      • 2013-01-12
      • 2011-07-31
      • 2011-07-05
      • 2019-07-13
      • 2018-05-14
      • 1970-01-01
      • 2012-03-25
      相关资源
      最近更新 更多