CORS POST请求可以使用普通的javascript,但为什么不使用jQuery?

A CORS POST request works from plain javascript, but why not with jQuery?

我正试图提出一个跨源站的帖子请求,我让它在简单的javascript中工作,如下所示:

1
2
3
4
5
6
7
8
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,但是我不能让它工作。这就是我要尝试的:

1
2
3
4
5
6
7
$.ajax(url, {
    type:"POST",
    dataType:"json",
    data:{action:"something"},
    success:function(data, textStatus, jqXHR) {alert("success");},
    error: function(jqXHR, textStatus, errorThrown) {alert("failure");}
});

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

(我正在使用jquery 1.5.1和firefox 4.0,我的服务器正在使用一个适当的访问控制allow origin头文件进行响应)


更新:正如Timk指出的那样,jquery 1.5.2不再需要这个了。但是,如果您想添加自定义头文件或允许使用凭据(用户名、密码或cookie等),请继续阅读。

我想我找到了答案!(4个小时后,大量咒骂)

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

您需要手动指定要接受的所有头文件(至少在FF 4.0&chrome 10.0.648.204中是这样)。

jquery的$.ajax方法发送所有跨域请求的"x-requested-with"头(我认为它是唯一的跨域请求)。

因此,响应选项请求所需的缺失头是:

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

如果传递的是任何非"简单"头,则需要将其包含在列表中(我再发送一个):

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

所以要把它们放在一起,这里是我的PHP:

1
2
3
4
5
6
7
8
9
10
11
12
13
// * 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);
}


另一种可能是设置dataType: json导致jquery发送Content-Type: application/json头。这被CORS视为非标准头段,需要CORS飞行前请求。所以有几点需要尝试:

1)尝试配置服务器以发送正确的飞行前响应。这将以附加头文件的形式出现,如Access-Control-Allow-MethodsAccess-Control-Allow-Headers

2)降低dataType: json设置。jquery在默认情况下应该请求Content-Type: application/x-www-form-urlencoded,但为了确保可以用contentType: 'application/x-www-form-urlencoded'替换dataType: json


您正在发送JS中的"params":request.send(params);

但jquery中的"数据"。是否定义了数据?:data:data,

此外,URL中还有一个错误:

1
2
3
4
5
6
7
$.ajax( {url:url,
         type:"POST",
         dataType:"json",
         data:data,
         success:function(data, textStatus, jqXHR) {alert("success");},
         error: function(jqXHR, textStatus, errorThrown) {alert("failure");}
});

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

更新:我是根据先生的回答在谷歌上搜索的,我发现你需要添加Access-Control-Allow-Headers: Content-Type(以下是完整的段落)

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

How CORS Works

CORS works very similarly to Flash's
crossdomain.xml file. Basically, the
browser will send a cross-domain
request to a service, setting the HTTP
header Origin to the requesting
server. The service includes a few
headers like
Access-Control-Allow-Origin to
indicate whether such a request is
allowed.

For the BOSH connection managers, it
is enough to specify that all origins
are allowed, by setting the value of
Access-Control-Allow-Origin to *. The
Content-Type header must also be
white-listed in the
Access-Control-Allow-Headers header.

Finally, for certain types of
requests, including BOSH connection
manager requests, the permissions
check will be pre-flighted. The
browser will do an OPTIONS request and
expect to get back some HTTP headers
that indicate which origins are
allowed, which methods are allowed,
and how long this authorization will
last. For example, here is what the
Punjab and ejabberd patches I did
return for OPTIONS:

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


按以下方式修改jquery:

1
2
3
4
5
6
7
8
9
$.ajax({
            url: someurl,
            contentType: 'application/json',
            data: JSONObject,
            headers: { 'Access-Control-Allow-Origin': '*' }, //add this line
            dataType: 'json',
            type: 'POST',                
            success: function (Data) {....}
});