一个CORS POST请求可以在普通JavaScript上运行,但是为什么不使用jQuery?


87

我正在尝试发出跨源发帖请求,并且使它JavaScript像下面这样简单地工作:

var request = new XMLHttpRequest();
var params = "action=something";
request.open('POST', url, true);
request.onreadystatechange = function() {if (request.readyState==4) alert("It worked!");};
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.setRequestHeader("Content-length", params.length);
request.setRequestHeader("Connection", "close");
request.send(params);

但是我想使用jQuery,但是我无法使用它。这是我正在尝试的:

$.ajax(url, {
    type:"POST",
    dataType:"json",
    data:{action:"something"}, 
    success:function(data, textStatus, jqXHR) {alert("success");},
    error: function(jqXHR, textStatus, errorThrown) {alert("failure");}
});

这导致失败。如果有人知道为什么jQuery不起作用,请告诉我们。谢谢。

(我正在使用jQuery1.5.1和Firefox 4.0,并且我的服务器使用正确的Access-Control-Allow-Origin标头进行响应)


这是我的解决方案(使用Javascript的XMLHttpRequest),同时
遇到

Answers:


73

更新:正如TimK所指出的,jQuery 1.5.2不再需要此功能。但是,如果要添加自定义标题或允许使用凭据(用户名,密码或cookie等),请继续阅读。


我想我找到了答案!(4小时和很多诅咒)

//This does not work!!
Access-Control-Allow-Headers: *

您需要手动指定您将接受的所有标头(至少在FF 4.0和Chrome 10.0.648.204中对我来说是这种情况)。

jQuery的$ .ajax方法为所有跨域请求(我认为这是唯一的跨域)发送“ x-requested-with”标头。

因此,响应OPTIONS请求所需的缺少标头是:

//no longer needed as of jquery 1.5.2
Access-Control-Allow-Headers: x-requested-with

如果要传递任何非“简单”标头,则需要将它们包括在列表中(我还要发送一个):

//only need part of this for my custom header
Access-Control-Allow-Headers: x-requested-with, x-requested-by

综上所述,这是我的PHP:

// * wont work in FF w/ Allow-Credentials
//if you dont need Allow-Credentials, * seems to work
header('Access-Control-Allow-Origin: http://www.example.com');
//if you need cookies or login etc
header('Access-Control-Allow-Credentials: true');
if ($this->getRequestMethod() == 'OPTIONS')
{
  header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
  header('Access-Control-Max-Age: 604800');
  //if you need special headers
  header('Access-Control-Allow-Headers: x-requested-with');
  exit(0);
}

5
请注意,jQuery 1.5.2更改了其行为。它不再添加“ X-Requested-With”标头,因此可能不再是问题。blog.jquery.com/2011/03/31/jquery-152-released(错误8423)
Magmatic

1
@TimK,你是对的!我没有注意到他们发布了1.5.2。话虽如此,如果您需要对其进行预检,这也可以使用。我已经更新了答案。
Will Mason

所以,我很困惑。您最终还是不得不编写一个中间PHP脚本吗?因此,您不必担心使用Ajax,对吗?还是我错过了一些东西。有没有仅JavaScript的解决方案?
伊丽莎白

1
@Elisabeth此方法仅在您控制请求的目标时才有效...它不是中间脚本。它是我们所请求位置的PHP的顶部。这更有意义吗?
Will Mason

2
是! 谢谢威尔。我以为您可以从客户端控制所有内容,但是听起来您需要同时控制两端。
伊丽莎白,

18

另一种可能是该设置dataType: json导致JQuery发送Content-Type: application/json标头。这被CORS视为非标准标头,并且需要CORS预检请求。因此,请尝试以下几件事:

1)尝试配置服务器以发送正确的预检响应。这将采用附加标头(如Access-Control-Allow-Methods和)的形式Access-Control-Allow-Headers

2)放弃dataType: json设置。jQuery应该Content-Type: application/x-www-form-urlencoded默认请求,但是可以肯定的是,您可以将替换dataType: jsoncontentType: 'application/x-www-form-urlencoded'


感谢您的想法。我试过不设置dataType,而是将其设置为application/x-www-form-urlencodedand text/plain。而且我尝试添加响应标头,但Access-Control-Allow-Methods "POST, GET, OPTIONS"没有任何效果。
Magmatic

您可以查看JavaScript错误控制台(或Firebug的控制台),看看请求期间是否有任何错误?另外,如果您知道如何使用Wireshark,则可以使用它来查看实际的HTTP请求。
monsur 2011年

1
“另一种可能是设置dataType:json导致JQuery发送Content-Type:application / json标头” –这不会发生。dataType影响Accept请求标头,但不影响请求标Content-Type头。
昆汀

9

您正在js中发送“参数”: request.send(params);

但是在jQuery中是“数据”。是否定义了数据?: data:data,

另外,您在URL中有一个错误:

$.ajax( {url:url,
         type:"POST",
         dataType:"json",
         data:data, 
         success:function(data, textStatus, jqXHR) {alert("success");},
         error: function(jqXHR, textStatus, errorThrown) {alert("failure");}
});

您正在将语法与$ .post的语法混合


更新:我根据monsur的答案在谷歌上搜索,发现您需要添加Access-Control-Allow-Headers: Content-Type(以下是全文)

http://metajack.im/2010/01/19/crossdomain-ajax-for-xmpp-http-binding-made-easy/

CORS如何运作

CORS的工作方式与Flash的crossdomain.xml文件非常相似。基本上,浏览器将向服务发送跨域请求,将HTTP标头Origin设置为请求服务器。该服务包括一些标头,例如Access-Control-Allow-Origin,以指示是否允许这种请求。

对于BOSH连接管理器,只需将Access-Control-Allow-Origin的值设置为*,指定允许所有源即可。Content-Type标头还必须在Access-Control-Allow-Headers标头中列入白名单。

最后,对于某些类型的请求,包括BOSH连接管理器请求,权限检查将被预先取消。浏览器将执行OPTIONS请求,并期望返回一些HTTP标头,这些标头指示允许哪些起源,允许哪些方法以及该授权将持续多长时间。例如,这是我为OPTIONS返回的Punjab和ejabberd补丁:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type 
Access-Control-Max-Age: 86400

1
抱歉。是。var data = {action:"something"}
Magmatic

您可以在此处比较这两个函数的语法:api.jquery.com/jQuery.post
Aleadam 2011年

我只是用设置中的url尝试过,但是同样的问题。.ajax函数可以采用任何一种方式。
Magmatic

我已经有两个标题了。我添加了另外两个。仍然与jQuery“失败”。普通的javascript仍然有效。
Magmatic

我能想到的最后一件事是使用api.jquery.com/jQuery.ajaxSetup设置jQuery.ajaxSetup({'beforeSend': function(xhr) {xhr.setRequestHeader(string, string)}})和播放发送的不同标头(此处是rails的示例:railscasts.com/episodes/136-jquery
Aleadam

1

Cors会在完成请求之前将请求方法从POST更改为OPTIONS,因此不会发送您的发布数据。解决此cors问题的方法是使用ajax执行请求,而ajax不支持OPTIONS方法。示例代码:

        $.ajax({
            type: "POST",
            crossdomain: true,
            url: "http://localhost:1415/anything",
            dataType: "json",
            data: JSON.stringify({
                anydata1: "any1",
                anydata2: "any2",
            }),
            success: function (result) {
                console.log(result)
            },
            error: function (xhr, status, err) {
                console.error(xhr, status, err);
            }
        });

在C#服务器上具有以下标头:

                    if (request.HttpMethod == "OPTIONS")
                    {
                          response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
                          response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
                          response.AddHeader("Access-Control-Max-Age", "1728000");
                    }
                    response.AppendHeader("Access-Control-Allow-Origin", "*");

-2

通过以下方式修改您的Jquery:

$.ajax({
            url: someurl,
            contentType: 'application/json',
            data: JSONObject,
            headers: { 'Access-Control-Allow-Origin': '*' }, //add this line
            dataType: 'json',
            type: 'POST',                
            success: function (Data) {....}
});

为什么要使我的Ajax Callas同步!?
Radko Dinev

contentType: 'application/json', data: JSONObject,—服务器不希望使用JSON,因此发送JSON毫无意义。也没有JSON Object这样的东西
昆汀

1
headers: { 'Access-Control-Allow-Origin': '*' }, //add this line绝对不要那样做。Access-Control-Allow-Origin响应头,不是请求头。充其量,这无能为力。在最坏的情况下,它将把请求从简单的请求转换为预检的请求,这使得服务器上的处理变得更加困难。
昆汀
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.