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

Posted

技术标签:

【中文标题】Chrome 中的 AJAX 发送选项而不是 GET/POST/PUT/DELETE?【英文标题】:AJAX in Chrome sending OPTIONS instead of GET/POST/PUT/DELETE? 【发布时间】:2014-03-14 00:48:31 【问题描述】:

我正在开发一个内部网络应用程序。在 IE10 中,请求工作正常,但在 Chrome 中,所有 AJAX 请求(有很多)都是使用 OPTIONS 发送的,而不是我给它的任何定义的方法。从技术上讲,我的请求是“跨域”。该站点在 localhost:6120 上提供服务,我向其发出 AJAX 请求的服务在 57124 上。This closed jquery bug 定义了问题,但不是真正的修复。

如何在 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"
);

【问题讨论】:

该错误报告中的最后一条评论很好地解释了它...... 这让我大吃一惊,因为我所做的一切都非常普通(而且我的代码类似于 jquery 错误中的代码)。除此之外,这不是不包括它的借口。 BRB,获取一些示例代码。 请注意,IE 在确定请求是否跨域时不会考虑端口号。 @KevinB:我们的 REST 服务利用不同的请求,根据 http 方法做不同的事情。将所有内容切换为 GET 不是有效的修复方法。另外,根据 Dark Falcon 的回答,无论如何它都无济于事,因为我在请求中有 X-UserName 和其他自定义标头。 这并没有改变这样一个事实,即如果您要发出跨域请求,则必须遵循适用于跨域请求的所有规则才能使其正常工作。跨域请求通常涉及一个 OPTIONS 请求。处理得当,问题就会消失。解决此问题的唯一其他方法(不更改 api)是在与使用服务器端代码与 api 交互的主页面相同的服务器上拥有一个脚本。 【参考方案1】:

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

与简单的请求(上面讨论过)不同,“预检”请求首先 通过 OPTIONS 方法向资源上的资源发送 HTTP 请求 其他域,以判断实际请求是否安全 发送。跨站点请求是这样预检的,因为它们可能 对用户数据有影响。特别是,请求是 预检如果:

它使用 GET、HEAD 或 POST 以外的方法。此外,如果 POST 用于发送 Content-Type 以外的请求数据 application/x-www-form-urlencoded、multipart/form-data 或 text/plain, 例如如果 POST 请求使用 application/xml 或 text/xml,然后预检请求。 它在请求中设置自定义标头(例如,请求使用诸如 X-PINGOTHER 之类的标头)

【讨论】:

自定义标题。这可能是引发预检 OPTIONS 调用的原因。【参考方案2】:

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

即使你设置了也会发生这种情况

crossOrigin: false;

或者即使你省略它。

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

【讨论】:

【参考方案3】:

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

如果这不是跨域 ajax 调用,请尝试使您的目标 url 相对,看看问题是否消失。如果你真的绝望地研究 JSONP,但要小心,混乱潜伏着。我们真的无法为您提供更多帮助。

【讨论】:

我们的系统结构是我无法改变的。使用不同的端口是我们架构的要求。我得到相同的原产地政策,但认为我们实施的 CORS 就足够了。显然不是。 如果您的服务器返回 JSON 响应,您可以查看 JSONP 方法,负责任地使用它。 我真的不想和你争论,但是 JSONP 使用脚本标签从另一个域中提取数据,然后将结果发送到回调函数。如果结果不是 json,那就更难了。 不,难度不大。事实上,在任何情况下响应都不应该是有效的 JSON。相反,服务器应该返回如下内容:callbackfunc(somedata)。如您所见,这不是有效的 JSON。而且,somedata 可以是字符串、数字或任何你想要的。 我正在使用 Postman,并且请求方法已正确发送(例如“PUT”、“DELETE”等)。但是当我尝试从我的代码中执行此操作时,它总是使用请求方法 OPTIONS 发送它们。我不知道邮递员是怎么做到的。【参考方案4】:

如果可以通过使用不同名称的常规 GET/POST 传递参数,并让您的服务器端代码处理它。

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

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

【讨论】:

【参考方案5】:

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

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

希望对你有帮助!

【讨论】:

【参考方案6】:

作为@Dark Falcon 的answered,我简单地处理了它

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

所以在我的创建会话如果不存在的应用程序中,我只是添加了一个检查方法是否为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(); 
        
    

【讨论】:

【参考方案7】:

“preflighted”请求首先通过OPTIONS方法向另一个域上的资源发送一个HTTP请求,以确定实际请求是否可以安全发送。跨站请求

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

【讨论】:

您能补充一点信息吗?您的回答看起来像评论。 :)【参考方案8】:

考虑使用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 运行良好。

【讨论】:

Axios 也使用第一个 OPTIONS【参考方案9】:

我遇到了一个非常相似的问题。我花了将近半天的时间来了解为什么一切都在 Firefox 中正常工作而在 Chrome 中失败。就我而言,这是因为我的请求标头中的字段重复(或可能输入错误)。

【讨论】:

【参考方案10】:

使用fetch而不是XHR,那么即使是跨域的请求也不会被prelighted。

【讨论】:

【参考方案11】:
 $.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: 'text/plain; charset=utf-8',或者只是 contentType: 'text/plain',对我有用! 问候!!

【讨论】:

这和这个问题有什么关系? 嗨,我认为这解决了标题中的问题,使用这种内容类型,您可以通过 OPTIONS 方法。问候 ContentType 与方法无关。 我知道你在说什么,但试一试。根据浏览器,您的内容类型会影响您的请求并更改您的方法!

以上是关于Chrome 中的 AJAX 发送选项而不是 GET/POST/PUT/DELETE?的主要内容,如果未能解决你的问题,请参考以下文章

如何在java脚本中打开Chrome中的新选项卡而不是新窗口

chrome调试器:单击控制台中的异常链接会在新选项卡中打开文件,而不是交叉链接到源文件

同一站点的多个选项卡是不是发送多个 ajax 调用?

(Django) AJAX 请求的 CSRF 验证在 Chrome 而不是 Firefox 中工作

Internet Explorer 从 ajax 调用中插入选择选项

Chrome 不知道 POST 请求