CORS POST 请求通过纯 JavaScript 工作,但为什么不使用 jQuery?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5584923/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:55:53  来源:igfitidea点击:

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

javascriptjqueryxmlhttprequestcors

提问by Magmatic

I'm trying to make a Cross Origin post request, and I got it working in plain JavaScriptlike this:

我正在尝试发出一个跨源发布请求,我让它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);

But I would like to use jQuery, but I can't get it to work. This is what I'm trying:

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

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

This results in Failure. If anyone knows why jQuerydoesn't work, please let us all know. Thanks.

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

(I'm using jQuery1.5.1, and Firefox 4.0, and my server is responding with a proper Access-Control-Allow-Originheader)

(我使用的是jQuery1.5.1 和 Firefox 4.0,我的服务器以正确的Access-Control-Allow-Origin标头响应)

采纳答案by Will Mason

UPDATE: As TimK pointed out, this isn't needed with jquery 1.5.2 any more. But if you want to add custom headers or allow the use of credentials (username, password, or cookies, etc), read on.

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



I think I found the answer! (4 hours and a lot of cursing later)

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

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

You need to manually specify all the headers you will accept (at least that was the case for me in FF 4.0 & Chrome 10.0.648.204).

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

jQuery's $.ajax method sends the "x-requested-with" header for all cross domain requests (i think its only cross domain).

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

So the missing header needed to respond to the OPTIONS request is:

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

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

If you are passing any non "simple" headers, you will need to include them in your list (i send one more):

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

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

So to put it all together, here is my PHP:

综上所述,这是我的 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);
}

回答by monsur

Another possibility is that setting dataType: jsoncauses JQuery to send the Content-Type: application/jsonheader. This is considered a non-standard header by CORS, and requires a CORS preflight request. So a few things to try:

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

1) Try configuring your server to send the proper preflight responses. This will be in the form of additional headers like Access-Control-Allow-Methodsand Access-Control-Allow-Headers.

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

2) Drop the dataType: jsonsetting. JQuery should request Content-Type: application/x-www-form-urlencodedby default, but just to be sure, you can replace dataType: jsonwith contentType: 'application/x-www-form-urlencoded'

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

回答by Aleadam

You are sending "params" in js: request.send(params);

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

but "data" in jquery". Is data defined?: data:data,

但是 jquery 中的“数据”。数据是否已定义?: data:data,

Also, you have an error in the URL:

此外,您在 URL 中有错误:

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

You are mixing the syntax with the one for $.post

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



Update: I was googling around based on monsur answer, and I found that you need to add Access-Control-Allow-Headers: Content-Type(below is the full paragraph)

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

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

http://metaHyman.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:

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

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

回答by Lucas silva de souza sandim

Cors change the request method before it's done, from POST to OPTIONS, so, your post data will not be sent. The way that worked to handle this cors issue, is performing the request with ajax, which does not support the OPTIONS method. example code:

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

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


with this headers on c# server:

在 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", "*");

回答by Soma Sarkar

Modify your Jquery in following way:

按以下方式修改您的 Jquery:

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