Access-Control-Allow-Origin 错误但请求通过

Access-Control-Allow-Origin error but request goes through

我目前正在向我的实时服务器部署一个基本的 API,我 运行 陷入(我认为是)CORS 问题,但我可以进行一些行为'解释一下。

我正在从 AngularJS 前端与 Laravel 5 (+ laravel-cors) 后端通信。

我开始使用一个简单的 jQuery AJAX 调用(如下)进行测试,当我从本地 Vagrant 环境 (http://dev.example.local/test.html) 向 http://api.example.com/v1/matches 发出请求时,我收到关于 Access-Control-Allow-Origin 的错误。奇怪的是请求确实通过了,因为信息通过基于 Laravel 的 API 正确存储在数据库中。

$.ajax({
    method: 'POST',
    url: 'http://api.example.com/v1/players',
    data: {
        "username": "username",
        "first_name": "First",
        "last_name": "Last",
        "nickname": ""
    }
}).always(function(r) {
    console.log(r);
});

错误:

XMLHttpRequest cannot load http://api.example.com/v1/players. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://other.example.com' is therefore not allowed access.

console.log(r)returns{readyState: 0, responseJSON: undefined, status: 0, statusText: "error"}

我使用 Homestead VM (API) 和 Vagrant 环境(应用程序)在本地开发了应用程序,它在这些环境中正常工作...

一些观察:

欢迎任何有关如何进一步调试此问题的想法...我一整天都在努力解决这个问题,但我只是不知道是什么原因造成的。

您的服务器必须在响应中 return 适当的 Access-Control-Allow-Origin header。例如,如果请求是从 http://whosebug.com, then your server must return this header: Access-Control-Allow-Origin: http://whosebug.com. You can determine, server-side, what the origin is by looking at the Origin header on the request. If your server does not return this header in the response, you will not have any access to the properties of the response browser-side (such as the status code, headers, or message body). The Same Origin Policy 发送的,则处于此限制的中心。

当请求由 Postman 或 PhpStorm 的 RESTful 服务测试器发送时,您没有看到任何类似问题的原因是这些服务随请求发送 Origin header,因为它们不受同源策略的约束。默认情况下,浏览器会将此 header 附加到任何 cross-origin ajax 请求,因为浏览器 受同源策略约束。在我之前的场景中,请求 header 将如下所示:Origin: http://whosebug.com。实现 the CORS spec 的浏览器需要添加此请求 header 以便服务器能够确定请求的来源是否已列入 cross-origin ajax 请求的白名单。如果是这种情况,服务器将 return 正确的 Access-Control-Allow-Origin header。如果不是,它可以简单地省略 header。不实现 CORS 规范的浏览器将简单地拒绝发送这样的 ajax 请求。

关于您对为什么首先发送请求感到困惑,这归结为 "simple" 和 "non-simple" CORS 请求之间的区别。对于简单的 CORS 请求,请求将 总是 发送到服务器,但 client/JS 将无法在没有服务器正确确认的情况下解析响应。可以这么说,一些 CORS 请求 简单。例如,DELETEPATCH 请求,或包含 non-standard header 的 POST/GET 请求(例如 X-headers 或 "application/json" 的 Content-Type 而不是 "multipart/form-data")。换句话说,如果没有 JavaScript 就无法发送,则请求 简单。例如,<form> 提交或来自 <script src="..."> 的 GET 请求将始终发送 "simple" 请求。对于 non-simple 请求,浏览器必须 "preflight" 请求。这意味着浏览器发送一个中间请求,称为预检, 原始请求之前。此预检请求是 OPTIONS 请求。服务器必须比 return header 响应此预检确认原始请求的任何 non-standard 属性。如果是,则浏览器将发送原始请求。

您可以在 MDN 上阅读有关预检和 CORS 的更多信息。