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.