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

IT技术 javascript jquery xmlhttprequest cors
2021-02-06 11:40:31

我正在尝试发出跨源发布请求,我让它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标头响应

5个回答

更新:正如 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);
}
@TimK,你说得对!我没有注意到他们发布了 1.5.2。话虽如此,如果您需要预先飞行,这也适用。我已经更新了我的答案。
2021-03-12 11:40:31
所以,我很困惑。无论如何,您最终不得不编写一个中间 PHP 脚本?那么您就不必担心使用 Ajax 了,对吧?或者我错过了什么。没有 JavaScript 唯一的解决方案吗?
2021-03-29 11:40:31
@Elisabeth 此方法仅在您控制请求的目的地时才有效……它不是中间脚本。它是我们请求位置的 PHP 顶部。这样做更有意义吗?
2021-04-01 11:40:31
是的!谢谢威尔。我以为你可以从客户端控制一切,但听起来你需要控制两端。
2021-04-04 11:40:31
请注意,jQuery 1.5.2 已更改其行为。它不再添加“X-Requested-With”标头,因此这可能不再是问题。blog.jquery.com/2011/03/31/jquery-152-released (Bug 8423)
2021-04-08 11:40:31

另一种可能性是设置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默认请求,但可以肯定的是,您可以替换dataType: jsoncontentType: 'application/x-www-form-urlencoded'

谢谢你的想法。我尝试不设置数据类型,并将其设置为application/x-www-form-urlencoded甚至text/plain. 我尝试添加一个Access-Control-Allow-Methods "POST, GET, OPTIONS"没有工作的响应头
2021-03-13 11:40:31
“另一种可能性是设置 dataType: json 会导致 JQuery 发送 Content-Type: application/json 标头”——这不会发生。dataType影响Accept请求头,但不影响Content-Type请求头。
2021-03-17 11:40:31
能否查看 JavaScript 错误控制台(或 Firebug 的控制台)并查看请求过程中是否有任何错误?此外,如果您知道如何使用 Wireshark,则可以使用它来查看通过网络传输的实际 HTTP 请求。
2021-04-05 11:40:31

您在 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
我只是在设置中使用 url 尝试过,但同样的问题。.ajax 函数可以采用任何一种方式。
2021-03-25 11:40:31
我能想到的最后一件事是使用api.jquery.com/jQuery.ajaxSetup来设置jQuery.ajaxSetup({'beforeSend': function(xhr) {xhr.setRequestHeader(string, string)}})和播放发送的不同标头(此处为 rails 的示例:railscasts.com/episodes/136-jquery
2021-03-26 11:40:31
我已经有两个这样的标题了。我加了另外两个。jQuery 仍然“失败”。普通的 javascript 仍然有效。
2021-04-06 11:40:31
对不起。是的。var data = {action:"something"}
2021-04-10 11:40:31
您可以在此处比较这两个函数的语法:api.jquery.com/jQuery.post
2021-04-11 11:40:31

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

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

按以下方式修改您的 Jquery:

$.ajax({
            url: someurl,
            contentType: 'application/json',
            data: JSONObject,
            headers: { 'Access-Control-Allow-Origin': '*' }, //add this line
            dataType: 'json',
            type: 'POST',                
            success: function (Data) {....}
});
headers: { 'Access-Control-Allow-Origin': '*' }, //add this line——永远不要那样做。Access-Control-Allow-Origin响应头,而不是请求头。充其量这不会做任何事情。在最坏的情况下,它会将请求从简单请求转换为预检请求,这使得在服务器上处理变得更加困难。
2021-03-19 11:40:31
contentType: 'application/json', data: JSONObject,— 服务器不需要 JSON,因此发送 JSON 没有意义。没有 JSON Object 这样的东西
2021-03-21 11:40:31
为什么我想让我的 Ajax 调用同步!?
2021-03-22 11:40:31