响应预检请求未通过访问控制检查 - 没有'Access-Control-Allow-Origin'头部

710
我在使用ngResource调用REST API时遇到了这个错误,API是在Amazon Web Services上的:

XMLHttpRequest无法加载http://server.apiurl.com:8000/s/login?login=facebook。预检请求的响应未通过访问控制检查:所请求的资源上没有'Access-Control-Allow-Origin'头部。因此,来自'http://localhost'的访问被拒绝。错误 405

服务:

socialMarkt.factory('loginService', ['$resource', function ($resource) {
    var apiAddress = "http://server.apiurl.com:8000/s/login/";
    return $resource(apiAddress, {
        login: "facebook",
        access_token: "@access_token",
        facebook_id: "@facebook_id"
    }, {
        getUser: {
            method: 'POST'
        }
    });
}]);

控制器:

[...]
loginService.getUser(JSON.stringify(fbObj)),
    function (data) {
        console.log(data);
    },
    function (result) {
        console.error('Error', result.status);
    }
[...]

我正在使用Chrome。为了解决这个问题,我还能做些什么?

我甚至已经配置了服务器以接受来自localhost的头信息。


1
你是在“配置服务器”还是在“亚马逊网络服务上创建REST API”? - dandavis
3
你显然没有在服务器端足够地启用CORS。请提供响应头的示例。 - charlietfl
4
不管怎样,你的负评都是错误的。他正在将文件托管在本地计算机上。无论他在后端进行什么样的配置,都没有意义。Angular 不会允许这种预检请求。 - user796446
3
谢谢您的评论,在我将浏览器安全设置关闭后,问题得以解决。 - Andre Mendes
3
但是关闭安全性只是一种牺牲安全性的丑陋权宜之计,无法解决你的问题。 - shivi
显示剩余3条评论
28个回答

6

如果你正在使用Python的Flask服务器,你可以使用flask-cors插件启用跨域请求。

详情请参见:Flask-CORS


5

我们的团队偶尔会使用Vue.jsAxios和C# Web API。在你尝试访问的端点上添加路由属性可以为我们解决这个问题。

[Route("ControllerName/Endpoint")]
[HttpOptions, HttpPost]
public IHttpActionResult Endpoint() { }

这段代码是用什么语言写的?C#?还是Java - Peter Mortensen
抱歉@PeterMortensen的耽搁 - 这是用C#编写的。 - w00ngy

4

如果您正在使用API Gateway的HTTP API和代理路由 ANY / {proxy +}

您需要明确定义路由方法才能使CORS正常工作。

Enter image description here

我希望AWS文档中有关为HTTP API配置CORS的说明更加明确。
我与AWS支持团队通话了两个小时,他们联系了一位资深的HTTP API开发人员,并得出了这个建议。

4

对于那些使用API网关的Lambda集成代理的人,您需要将Lambda函数配置为直接向其提交请求,这意味着该函数应正确设置响应标头。(如果您使用自定义Lambda函数,则API网关将处理此操作。)

// In your lambda's index.handler():
exports.handler = (event, context, callback) => {
    // On success:
    callback(null, {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Origin" : "*"
        }
    }
}

1
我也想插一句话并提到一个大问题,我认为AWS没有记录。假设您使用API网关代理Lambda函数,并在该Lambda函数中使用某些API。如果该API返回非200成功代码,并且您没有将非200成功代码添加到API网关中的方法响应中,则会收到错误消息而看不到成功的响应。例如:Sendgrid和Twilio具有非200成功代码。 - Stephen Tetreault

3
跨域资源共享(CORS)是一种基于 HTTP 标头的机制,允许服务器指示任何来源(域名、方案或端口),除了自身之外,从中浏览器应允许加载资源。
简而言之——web 服务器告诉您(浏览器)应该信任哪些网站以使用站点。
  1. Scammysite.bad 尝试告诉您的浏览器向 good-api-site.good 发送请求
  2. good-api-site.good 告诉您的浏览器,它只应信任 other-good-site.good
  3. 您的浏览器说,您真的不应信任 scammysite.badgood-api-site.good 的请求,于是CORS 拯救了您

来自跨域资源共享(CORS) 如果您正在创建一个站点,并且您真的不关心谁与您进行集成。那就继续吧。在您的ACL中设置*
然而,如果您正在创建一个站点,并且只允许站点X,甚至是站点X、Y和Z进行集成,您可以使用CORS来指示客户端浏览器只信任这些站点与您的站点进行集成。
浏览器当然可以选择忽略这一点。再次强调,CORS保护的是您的客户端,而不是您自己。
CORS允许定义*一个站点。这可能会限制您,但您可以通过向Web服务器添加一些动态配置来解决这个问题 - 并且帮助您更具体地设置。
以下是在Apache中如何针对每个站点配置CORS的示例:
# Save the entire "Origin" header in Apache environment variable "AccessControlAllowOrigin"
# Expand the regex to match your desired "good" sites / sites you trust
SetEnvIfNoCase Origin "^https://(other-good-site\.good|one-more-good.site)$" AccessControlAllowOrigin=$0
# Assuming you server multiple sites, ensure you apply only to this specific site
<If "%{HTTP_HOST} == 'good-api-site.com'">
    # Remove headers to ensure that they are explicitly set
    Header        unset Access-Control-Allow-Origin   env=AccessControlAllowOrigin
    Header        unset Access-Control-Allow-Methods  env=AccessControlAllowOrigin
    Header        unset Access-Control-Allow-Headers  env=AccessControlAllowOrigin
    Header        unset Access-Control-Expose-Headers env=AccessControlAllowOrigin
    # Add headers "always" to ensure that they are explicitly set
    # The value of the "Access-Control-Allow-Origin" header will be the contents saved in the "AccessControlAllowOrigin" environment variable
    Header always set Access-Control-Allow-Origin   %{AccessControlAllowOrigin}e     env=AccessControlAllowOrigin
    # Adapt the below to your use case
    Header always set Access-Control-Allow-Methods  "POST, GET, OPTIONS, PUT"        env=AccessControlAllowOrigin
    Header always set Access-Control-Allow-Headers  "X-Requested-With,Authorization" env=AccessControlAllowOrigin
    Header always set Access-Control-Expose-Headers "X-Requested-With,Authorization" env=AccessControlAllowOrigin
</If>

3

我认为从Chrome禁用CORS不是一个好的方式,因为如果你在Ionic中使用它,特别是在手机建设时,问题会再次出现。

所以最好在你的后端修复它。

首先,在头部中,你需要设置-

  • header('Access-Control-Allow-Origin: *');
  • header('Header set Access-Control-Allow-Headers: "Origin, X-Requested-With, Content-Type, Accept"');

如果API同时作为GET和POST操作,则还要在头部中设置-

if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}"); exit(0); }


2
这个错误的一个非常普遍的原因可能是主机API将请求映射到了一个HTTP方法(例如PUT),而API客户端正在使用不同的HTTP方法(例如POSTGET)调用API。

1
当DNS服务器设置为8.8.8.8(Google的)时,我遇到了这个问题。实际上,问题出在路由器上。我的应用程序尝试通过Google连接服务器,而不是本地连接(针对我的特定情况)。我已经删除了8.8.8.8,问题得到解决。我知道这些问题可以通过CORS设置来解决,但也许有人会像我一样遇到同样的麻烦。

1

Enter image description here

在API网关中使用CORS选项,我使用了上面显示的以下设置。

另外,请注意,您的函数必须对OPTIONS请求返回HTTP状态200,否则CORS也会失败。


1
如果像我这样的可怜人正在使用Django和Nginx与Swagger UI,并且一直在尝试使用Docker和本地https工作端点,请确保您已经将Swagger配置设置为使用:'https://<local-domain.local>'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接