为啥我收到的是 OPTIONS 请求而不是 GET 请求?

Posted

技术标签:

【中文标题】为啥我收到的是 OPTIONS 请求而不是 GET 请求?【英文标题】:Why am I getting an OPTIONS request instead of a GET request?为什么我收到的是 OPTIONS 请求而不是 GET 请求? 【发布时间】:2010-11-18 09:37:12 【问题描述】:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js" type="text/javascript"></script>
<script>
$.get("http://example.com/", function(data) 
     alert(data);
);
</script>

它向那个 URL 发出一个 OPTIONS 请求,然后永远不会用任何东西调用回调。

当它不是跨域时,它可以正常工作。

jQuery 不应该只使用&lt;script&gt; 节点进行调用,然后在加载时进行回调吗?我知道我将无法获得结果(因为它是跨域的),但没关系;我只是想让电话通过。这是一个错误,还是我做错了什么?

【问题讨论】:

可能是跨域的 cos。例如,如果您在文件 File://PATH_TO_WEBSITE 而不是使用 localhost/WEBSITE_LINK 【参考方案1】:

根据MDN,

预检请求

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

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

【讨论】:

这解决了我们的问题,从“application/json”更改为“text/plain”停止了可怕的选项请求 我不明白为什么浏览器使用 OPTIONS 方法请求只是为了检查实际请求是否可以安全发送。但在什么意义上?我的意思是服务器也可以对某些响应标头进行限制,所以为什么需要这样做? @hardik 请记住,通过添加 CORS,您可能会接受来自任何人的请求,其中他们可以通过请求(POST、PUT、DELETE 等)操作您服务器上的数据。在这些情况下,例如使用自定义标头时,浏览器只是先与服务器检查服务器是否愿意在发送请求之前接受请求,因为向服务器发送未经请求的请求可能对您的数据非常危险,而且,什么是如果服务器不想接受它们,浏览器中的点发送可能很大的有效载荷,因此飞行前 OPTIONS 检查。 @davidnknight 如果将您的数据发送到服务器可能会很危险,这意味着服务器可能会受到威胁,那么恶意服务器当然会以“当然,全部发送!”来响应您的 OPTIONS 请求。 .那安全性如何? (诚​​实的问题) "预检请求不是安全问题。相反,它们是不改变规则的问题。" - 查看What is the Motivation Behind Introducing Preflight Requests的答案【参考方案2】:

选项来自http://www.w3.org/TR/cors/ 更多信息请参见http://metajack.im/2010/01/19/crossdomain-ajax-for-xmpp-http-binding-made-easy/

【讨论】:

【参考方案3】:

如果您尝试 POST

确保JSON.stringify您的表单数据并以text/plain发送。

<form id="my-form" onSubmit="return postMyFormData();">
    <input type="text" name="name" placeholder="Your Name" required>
    <input type="email" name="email" placeholder="Your Email" required>
    <input type="submit" value="Submit My Form">
</form>

function postMyFormData() 

    var formData = $('#my-form').serializeArray();
    formData = formData.reduce(function(obj, item) 
        obj[item.name] = item.value;
        return obj;
    , );
    formData = JSON.stringify(formData);

    $.ajax(
        type: "POST",
        url: "https://website.com/path",
        data: formData,
        success: function()  ... ,
        dataType: "text",
        contentType : "text/plain"
    );

【讨论】:

【参考方案4】:

我不相信 jQuery 在给定这样的 URL 时会自然地执行 JSONP 请求。但是,当您告诉它使用什么参数进行回调时,它会执行 JSONP 请求:

$.get("http://metaward.com/import/http://metaward.com/u/ptarjan?jsoncallback=?", function(data) 
     alert(data);
);

完全由接收脚本来使用那个参数(它不必被称为“jsoncallback”),所以在这种情况下这个函数永远不会被调用。但是,既然您说您只想执行 metaward.com 上的脚本,那就可以了。

【讨论】:

是否仍会通知我的回调脚本元素已完全加载?我只是想确保更新发生在我查询 API 之前。 如果接收脚本支持JSONP,并且愿意调用你识别的函数,你会的。如果脚本只生成一个没有其他行为的 JSON 数据块,那么您将无法判断它何时完成加载。如果必须知道何时完成加载,您可以考虑在您自己的服务器上实现一个充当代理的脚本。【参考方案5】:

事实上,出于安全原因,不允许跨域 AJAX (XMLHttp) 请求(考虑从客户端获取“受限”网页并将其发送回服务器——这将是一个安全问题) .

唯一的解决方法是回调。这是:创建一个新的脚本对象并将 src 指向端 JavaScript,这是一个带有 JSON 值的回调(myFunction(data),myFunction 是一个对数据执行某些操作的函数(例如,存储它)在变量中)。

【讨论】:

对,但我可以在 【参考方案6】:

只需将“application/json”更改为“text/plain”,不要忘记 JSON.stringify(request):

var request = Company: sapws.dbName, UserName: username, Password: userpass;
    console.log(request);
    $.ajax(
        type: "POST",
        url: this.wsUrl + "/Login",
        contentType: "text/plain",
        data: JSON.stringify(request),

        crossDomain: true,
    );

【讨论】:

【参考方案7】:

我遇到了同样的问题。我的解决方法是向我的 php 脚本添加标题,这些标题仅在开发环境中存在。

这允许跨域请求:

header("Access-Control-Allow-Origin: *");

这告诉预检请求客户端可以发送它想要的任何标头:

header("Access-Control-Allow-Headers: *");

这样就不需要修改请求了。

如果您的开发数据库中有可能泄露的敏感数据,那么您可能会三思而后行。

【讨论】:

【参考方案8】:

就我而言,这个问题与 CORS 无关,因为我向同一个 Web 服务器发出了 jQuery POST。数据是 JSON,但我省略了 dataType: 'json' 参数。

我没有(也没有添加)一个 contentType 参数,如上面 David Lopes 的回答所示。

【讨论】:

【参考方案9】:

我能够在以下标题的帮助下修复它

Access-Control-Allow-Origin
Access-Control-Allow-Headers
Access-Control-Allow-Credentials
Access-Control-Allow-Methods

如果您使用的是 Nodejs,这里是您可以复制/粘贴的代码。

app.use((req, res, next) => 
  res.header('Access-Control-Allow-Origin','*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH');
  next();
);

【讨论】:

【参考方案10】:

看起来 Firefox 和 Opera(也在 mac 上测试过)不喜欢这种跨域性(但 Safari 很好)。

您可能需要调用本地服务器端代码来 curl 远程页面。

【讨论】:

以上是关于为啥我收到的是 OPTIONS 请求而不是 GET 请求?的主要内容,如果未能解决你的问题,请参考以下文章

当 OPTIONS 请求的 statusCode 为 200 时,为啥我会在 API Gateway GET 请求中收到 CORS 错误?

Charles Proxy:映射到 GET 请求而不是 OPTIONS [关闭]

为啥在我的 Angular 2 应用程序中发送 OPTIONS 请求而不是 PUT? [复制]

为啥我用ajax请求后台会请求两次,一次get,一次OPTIONS,求解决

为啥 HttpClient.PostAsync 似乎将请求作为 GET 而不是 POST 发送?

Node.js GET 请求有时会收到 HTML 文档而不是 JSON 并崩溃