为什么我收到OPTIONS请求而不是GET请求?


288
<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是否不应该仅使用<script>节点进行调用,然后在加载时进行回调?我知道我将无法获得结果(因为它是跨域的),但是没关系;我只想打通电话。这是一个错误,还是我做错了什么?


2
可能是跨域的cos。例如,如果您使用文件File:// PATH_TO_WEBSITE而不是使用localhost / WEBSITE_LINK
James111,2015年

Answers:


262

根据MDN

事前要求

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

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

43
这解决了我们的问题,从“ application / json”更改为“ text / plain”停止了可怕的选项请求
Keeno

10
我不明白的是为什么浏览器要求使用OPTIONS方法只是为了检查实际请求是否可以安全发送。但是在什么意义上呢?我的意思是服务器还可以对某些响应标头设置限制,所以为什么需要这样做?
hardik

11
@hardik请记住,通过添加CORS,您可能会接受来自任何人的请求,他们可以在其中通过请求(POST,PUT,DELETE等)操纵服务器上的数据。在这种情况下,例如使用自定义标头时,浏览器只是在向服务器检查服务器是否愿意在发送请求之前接受该请求,因为向服务器发送未经请求的请求可能对您的数据确实很危险,并且如果服务器不想接受有效负载,则浏览器中的该点将发送可能较大的有效负载,因此进行飞行前OPTIONS检查。
davidnknight

6
@davidnknight如果将数据发送到服务器可能很危险,这意味着服务器可能受到威胁,那么恶意服务器当然会以“确定,将其全部发送!”响应您的OPTIONS请求。这种安全性如何?(诚​​实的问题)
马特

3
“预检请求不是安全的事情。相反,它们不是规则不变的事情。” -查看回答什么是引入预检要求背后的动机
FMJaguar


9

如果你想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"
    });
}

2

我不认为给定这样的URL时jQuery会自然地发出JSONP请求。但是,当您告诉它用于回调的参数时,它将执行JSONP请求:

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

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


我的回调仍会被通知脚本元素已完全加载吗?我只想确保更新发生在查询API之前。
Paul Tarjan

如果接收脚本支持JSONP,并且愿意调用您标识的函数,则将执行。如果脚本什么都不做,但是没有任何其他行为就生成了JSON数据块,则您将无法知道何时完成加载。如果必须告知何时完成加载,则可以考虑在自己的服务器上实现充当代理的脚本。
VoteyDisciple

1

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

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


1
是的,但是我可以将其加载到<script src =“”>或<img src =“”>中,浏览器会很高兴地将其选中。我只想知道何时完全加载,以便我可以查询导入结果。
Paul Tarjan

1

只需将“ 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,
    });

1

我有同样的问题。我的解决方法是将标头添加到PHP脚本中,这些标头仅在开发环境中存在。

这允许跨域请求:

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

这告诉预检请求,客户端可以发送所需的任何标头了:

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

这样就无需修改请求。

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


1

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

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


0

看起来Firefox和Opera(也已在Mac上进行了测试)不喜欢这种跨域性(但Safari很好用)。

您可能必须调用本地服务器端代码才能卷曲远程页面。


0

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

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