Chrome中的AJAX发送选项而不是GET / POST / PUT / DELETE吗?


107

我正在工作一个内部Web应用程序。在IE10中,请求工作正常,但在Chrome中,所有AJAX请求(很多)都是使用OPTIONS发送的,而不是我提供的任何已定义方法。从技术上讲,我的要求是“跨​​域”。该站点位于localhost:6120上,我向AJAX发出请求的服务位于57124上。此关闭的jquery错误定义了该问题,但不是真正的解决方法。

如何在ajax请求中使用正确的http方法?

编辑:

这在每页的文档加载中:

jQuery.support.cors = true;

每个AJAX的构建方式都类似:

var url = 'http://localhost:57124/My/Rest/Call';
$.ajax({
    url: url,
    dataType: "json",
    data: json,
    async: true,
    cache: false,
    timeout: 30000,
    headers: { "x-li-format": "json", "X-UserName": userName },
    success: function (data) {
        // my success stuff
    },
    error: function (request, status, error) {
        // my error stuff
    },
    type: "POST"
});

2
该错误报告中的最后一条评论很好地说明了这一点
— Kevin B

1
这让我大吃一惊,因为我所做的一切都太香草了(我的代码与jquery错误中的代码相似)。除此之外,不包含它也不是任何借口。BRB,获取一些示例代码。
— 科里·奥格本

3
请注意,在确定请求是否为跨域请求时,IE不会考虑端口号。
— 雷尼科尔斯

@KevinB:我们的REST服务利用不同的请求作为基于http方法的不同操作。将所有内容切换为GET无效。而且,根据Dark Falcon的回答,无论如何它都无济于事,因为我在请求中有X-UserName和其他自定义标头。
— 科里·奥格本

这并不会改变以下事实:如果您要进行跨域请求,则必须遵循适用于跨域请求的所有规则才能使其正常工作。跨域请求通常涉及一个OPTIONS请求。正确处理它,问题将消失。解决此问题的唯一其他方法(不更改api)是在与主页面位于同一服务器上的脚本中使用服务器端代码与api进行交互。
— 凯文B

Answers:


136

Chrome正在预检查找CORS标头的请求。如果请求可以接受,它将发送真实请求。如果您正在执行此跨域操作,则只需处理它,否则将找到一种使请求成为非跨域请求的方法。这就是为什么jQuery Bug无法修复而关闭的原因。这是设计使然。

与简单请求(如上所述)不同,“预检”请求首先通过OPTIONS方法将HTTP请求发送到另一个域上的资源,以确定实际请求是否可以安全发送。跨站点请求这样被预检,因为它们可能会影响用户数据。特别是在以下情况下,请求将被预检:

  • 它使用GET,HEAD或POST以外的方法。另外,如果POST用于发送请求类型为application / x-www-form-urlencoded,multipart / form-data或text / plain之外的Content-Type的请求数据,例如POST请求将XML有效负载发送给服务器使用application / xml或text / xml,则对请求进行预检。
  • 它在请求中设置自定义标头(例如,请求使用标头,例如X-PINGOTHER)

20
自定义标题。这可能是触发预检OPTIONS调用的原因。
— 科里·奥格本

18

基于请求未在默认端口80/443上发送的事实,此Ajax调用自动被视为跨域资源(CORS)请求,换句话说,该请求自动发出一个OPTIONS请求,该请求将检查服务器/ Servlet一侧的CORS标头。

即使您设置

crossOrigin: false;

或者即使您忽略它。

原因很简单localhost != localhost:57124。尝试仅将其发送到localhost没有端口的情况下-它将失败,因为无法达到所请求的目标,但是请注意,如果域名相等,则在POST之前发送的请求中没有OPTIONS请求。


3

我同意Kevin B,该错误报告说明了一切。听起来您正在尝试进行跨域Ajax调用。如果您不熟悉相同的原始政策,则可以从这里开始:https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Same_origin_policy_for_JavaScript。

如果不打算将其作为跨域Ajax调用,请尝试使目标url为相对URL,然后看问题是否消失。如果您真的很绝望,请查看JSONP,但请注意,混乱不堪。我们真的可以为您提供更多帮助。


1
我的系统结构是我无法更改的。使用其他端口是我们架构的要求。我得到了相同的原产地政策,但认为我们实施的CORS就足够了。显然不是。
— 科里·奥格本

2
如果您的服务器返回JSON响应,则可以调查JSONP方法,以负责任的方式使用它。
— jgitter 2014年

1
我真的不在乎与您争论,但是JSONP使用脚本标签从另一个域中提取数据,然后将结果发送到回调函数。如果结果不是json,则要困难得多。
— jgitter 2014年

1
不,这并不困难。实际上,无论如何,响应都不应该是有效的JSON。相反,服务器应返回以下内容:callbackfunc(somedata)。如您所见,这不是有效的JSON。并且,somedata可以是字符串,数字或任何您想要的名称。
— 雷尼科尔斯

1
我使用的是Postman,那里的请求方法已正确发送(例如,“ PUT”,“ DELETE”等)。但是,当我尝试从我的代码中执行此操作时,它始终使用请求方法OPTIONS发送给他们。我不知道邮递员是怎么做到的。
— ErwinGO,2015年

1

如果可能,请使用其他名称通过常规GET / POST传递参数,然后让服务器端代码进行处理。

我自己的代理绕过CORS时遇到了类似的问题,并且在Chrome中出现了POST-> OPTION的相同错误。Authorization在我的情况下("x-li-format"也是"X-UserName"您的情况),它是标头。我最终以虚拟格式(例如,AuthorizatinJack在GET中)传递它,并且更改了我的代理的代码,以便在调用目标时将其转换为标头。在PHP中:

if (isset($_GET['AuthorizationJack'])) {
    $request_headers[] = "Authorization: Basic ".$_GET['AuthorizationJack'];
}

1

就我而言,我正在调用由AWS托管的API(API网关)。当我尝试从API自己的域以外的域中调用API时,发生了错误。因为我是API所有者,所以我为测试环境启用了CORS,如Amazon Documentation中所述。

在生产中不会发生此错误,因为请求和api将位于同一域中。

希望对您有所帮助!


0

正如@Dark Falcon 回答的那样,我只是处理了它。

就我而言,我正在使用node.js服务器,并创建一个会话(如果不存在)。由于OPTIONS方法中没有会话详细信息,因此最终为每个POST方法请求创建了一个新会话。

因此,在我的应用程序例程中创建不存在会话,我只是添加了一个检查以查看method是否为OPTIONS,如果是,则跳过会话创建部分:

    app.use(function(req, res, next) {
        if (req.method !== "OPTIONS") {
            if (req.session && req.session.id) {
                 // Session exists
                 next();
            }else{
                 // Create session
                 next();
          }
        } else {
           // If request method is OPTIONS, just skip this part and move to the next method.
           next(); 
        }
    }


0

考虑使用axios

axios.get( url,
{ headers: {"Content-Type": "application/json"} } ).then( res => {

  if(res.data.error) {

  } else { 
    doAnything( res.data )
  }

}).catch(function (error) {
   doAnythingError(error)
});

我在使用fetch时遇到了这个问题,而axios则工作得很好。


5
Axios公司也使用第一OPTIONS
— Skylin - [R

0

我遇到了一个非常相似的问题。我花了将近半天的时间来理解为什么一切在Firefox中都能正常运行而在Chrome上却无法正常运行的原因。在我的情况下,这是因为我的请求标头中的字段重复(或类型错误)。


0

使用fetch代替XHR,那么即使请求是跨域的,请求也不会被预显示。


-1
 $.ajax({
            url: '###',
            contentType: 'text/plain; charset=utf-8',
            async: false,
            xhrFields: {
                withCredentials: true,
                crossDomain: true,
                Authorization: "Bearer ...."
            },

            method: 'POST',

            data: JSON.stringify( request ),
            success: function (data) {
                console.log(data);
            }
        });

contentType:“文本/纯文本;charset = utf-8'或仅contentType:'text / plain'对我有用!问候!!


这与这个问题有什么关系?
— 科里·奥格本

嗨,我认为这可以解决标题中的问题,使用此内容类型可以通过OPTIONS方法。问候
— David Lopes

ContentType与该方法无关。
— 科里·奥格本

我知道您在说什么,但请尝试一下。根据浏览器,您的内容类型可能会影响您的请求并更改您的方法!
— David Lopes
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.