对预检请求的响应未通过访问控制检查

Posted

技术标签:

【中文标题】对预检请求的响应未通过访问控制检查【英文标题】:Response to preflight request doesn't pass access control check 【发布时间】:2020-05-10 07:15:16 【问题描述】:

我在使用 ngResource 调用 Amazon Web Services 上的 REST API 时遇到此错误:

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 的标头。

【问题讨论】:

困惑:你是“配置服务器”还是这是“亚马逊网络服务上的休息 api”? 您显然做得还不够,无法在服务器端启用 CORS。发布响应标头示例 无论哪种方式,您的反对票都是错误的。他在他的本地机器上托管他的文件。他在后端做什么样的conf都没有关系。 Angular 不允许这种预飞行。 感谢 cmets,当我将浏览器设置为关闭安全时它起作用了 @Andre 但是关闭安全性只是一个丑陋的解决方法,您会损害安全性,并不能解决您的问题...... 【参考方案1】:

跨域资源共享 (CORS) 是一种基于 HTTP 标头的机制,它允许服务器指示除其自身以外的任何来源(域、方案或端口),浏览器 应该允许加载资源

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

简而言之 - 网络服务器告诉您(您的浏览器)您应该信任哪些网站使用网站。

    Scammysite.bad 尝试告诉您的浏览器向 good-api-site.good 发送请求 good-api-site.good 告诉您的浏览器它应该只信任 other-good-site.good 您的浏览器说您真的不应该相信 scammysite.badgood-api-site.good 的请求,然后 CORS 已保存你

如果您正在创建一个站点,并且您真的不在乎谁与您集成。继续犁。在 ACL 中设置 *

但是如果您正在创建一个站点,并且应该只允许站点 X,甚至站点 X、Y 和 Z,您可以使用 CORS 来指示客户浏览器只信任这些网站以与您的网站集成。

浏览器当然可以选择忽略这一点。同样,CORS 保护您的客户,而不是您。

CORS 允许定义*一个 站点。这可能会限制您,但您可以通过向您的网络服务器添加一些动态配置来解决这个问题 - 并且帮助您做到具体。

这是一个关于如何在 Apache 中配置 CORS pr 站点的示例:

# 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   %AccessControlAllowOrigine     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>

【讨论】:

【参考方案2】:

如果您正在编写 chrome-extension

您必须在manifest.json 中添加您的域的权限。

"permissions": [
   "http://example.com/*",
   "https://example.com/*",
   "http://www.example.com/*",
   "https://www.example.com/*"
]

【讨论】:

还要检查你是否有 www 前缀 这是一个救命稻草,因为关于扩展/插件的文档非常有限【参考方案3】:

您遇到了 CORS 问题。

有几种方法可以解决/解决此问题。

    关闭 CORS。例如:how to turn off cors in chrome Use a plugin for your browser 使用 nginx 等代理。 example of how to set up 为您的服务器完成必要的设置。这更多是您在 EC2 实例上加载的 Web 服务器的一个因素(假设这就是您所说的“Amazon Web 服务”)。对于您的特定服务器,您可以参考enable CORS website.

更详细地说,您正在尝试从 localhost 访问 api.serverurl.com。这就是跨域请求的准确定义。

通过关闭它只是为了完成您的工作(好的,但是如果您访问其他网站并且只是在路上踢罐子,那么您的安全性会很差)您可以使用代理,让您的浏览器认为所有请求都来自本地主机,当你真的有本地服务器,然后调用远程服务器。

所以 api.serverurl.com 可能会变成 localhost:8000/api 并且您的本地 nginx 或其他代理将发送到正确的目的地。


现在应大众需求,100% more CORS info....同样美味!


绕过 CORS 正是为那些只是学习前端的人所展示的。 https://codecraft.tv/courses/angular/http/http-with-promises/

【讨论】:

我添加了 chrome 插件,它工作了几天。现在它不工作了。 @Xvegas 您可以在此处查看您的服务器类型。 w3.org/wiki/CORS_Enabled 谢谢你拯救了我的一天。仅使用第一个选项:C:\Program Files (x86)\Google\Chrome\Application>chrome.exe --user-data-dir="C:\Chrome dev session" --disable-web-security。来自:***.com/questions/3102819/… 在浏览器中禁用 cors?这不是一个解决方案,它是一种解决方法,对真正需要启用 CORS 的人没有帮助。 @JonathanSimas 如前所述,这是继续开发工作的几种方法之一。变通方法是解决方案。您甚至会在我的回答中注意到,我说这安全性很差,真的只是把罐子踢到了路上。 ;-)【参考方案4】:

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

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

【讨论】:

【参考方案5】:

对于任何使用 Api Gateway 的 HTTP API 和代理路由的人 ANY /proxy+

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

希望这在AWS Docs for Configuring CORS for an HTTP API 中更明确

与 AWS Support 进行了 2 小时的通话,他们联系了一位提出此建议的高级 HTTP API 开发人员。

希望这篇文章可以为那些使用 Api Gateway HTTP API 的人节省一些时间和精力。

【讨论】:

这正是我的问题。谢谢!【参考方案6】:

关于 CORS,有一些注意事项。首先,它不允许使用通配符*,但不要拘泥于这个我在某处读过它,现在找不到这篇文章。

如果您从其他域发出请求,则需要添加允许来源标头。

 Access-Control-Allow-Origin: www.other.com 

如果您发出的请求会影响 POST/PUT/PATCH 等服务器资源,并且如果 mime 类型不同于以下 application/x-www-form-urlencodedmultipart/form-datatext/plain,则浏览器将自动进行预检OPTIONS 请求检查服务器是否允许。

因此您的 API/服务器需要相应地处理这些 OPTIONS 请求,您需要使用相应的 access control headers 进行响应,并且 http 响应状态代码需要为 200

标题应该是这样的,根据您的需要调整它们:

   Access-Control-Allow-Methods: GET, POST, PUT, PATCH, POST, DELETE, OPTIONS
   Access-Control-Allow-Headers: Content-Type
   Access-Control-Max-Age: 86400

max-age 标头很重要,在我的情况下,没有它就无法工作,我猜浏览器需要“访问权限”有效时长的信息。

此外,如果您正在制作例如来自不同域的 POST 请求和 application/json mime 您还需要添加前面提到的允许来源标头,所以它看起来像这样:

   Access-Control-Allow-Origin: www.other.com 
   Access-Control-Allow-Methods: GET, POST, PUT, PATCH, POST, DELETE, OPTIONS
   Access-Control-Allow-Headers: Content-Type
   Access-Control-Max-Age: 86400

当飞行前成功并获得所有需要的信息时,您的实际请求将被提出。

一般来说,无论是在初始请求还是飞行前请求中请求的 Access-Control 标头,都应在响应中给出以使其正常工作。

this link 上的 MDN 文档中有一个很好的示例,您还应该查看 this SO post

【讨论】:

这里是 Mozilla 文章,讨论如何不能使用通配符作为 cors 来源:Link 所以显然这仅适用于使用凭据时(如果我理解正确的话) 我正在使用通配符并提交一个不记名令牌来授权请求​​并且它工作正常,所以不确定我上面提供的链接是指关于凭据的什么。我的问题是,在 .Net Core 中构建我的 CORS 策略时,我没有添加 .AllowCredentials()。添加.AllowCredentials() 后一切正常。【参考方案7】:

只需几个步骤即可轻松解决此问题,无需担心任何事情。 请按照步骤解决。

    打开(https://www.npmjs.com/package/cors#enabling-cors-pre-flight) 进入安装并复制命令 npm install cors 通过节点终端安装 通过滚动转到简单用法(启用所有 CORS 请求)。然后复制并粘贴 你的项目中的完整声明并运行它......这肯定会工作...... 复制评论代码并粘贴到您的 app.js 或任何其他项目中并尝试一下..这将起作用。这将解锁每个跨源资源共享..所以我们可以在服务之间切换以供您使用

【讨论】:

var express = require('express') var cors = require('cors') var app = express() app.use(cors()) app.get('/products/:id ', function (req, res, next) res.json(msg: 'This is-enabled for all origins!') ) app.listen(80, function () console.log('CORS-启用网络服务器监听端口 80') ) 在我看来,这也仅在 express 节点应用程序中有效,而在其他任何应用程序中均无效。【参考方案8】:

要修复 Node JS 应用程序中的跨域请求问题:

npm i cors

只需将以下几行添加到app.js

let cors = require('cors')
app.use(cors())

【讨论】:

这仅适用于 express js 应用程序,并非所有节点应用程序 非 Express js 应用的任何解决方案? @iprashant 看看 cors lib 正在做什么并做同样的事情。 @AntiCZ 无需查看 cors.. 看看 express 它是如何使用 cors 作为中间件的.. 通过 cors api 路由您的所有请求...然后到您的实际 api... 【参考方案9】:

我正在使用 AWS sdk 进行上传,在花了一些时间在线搜索之后,我偶然发现了这个线程。感谢@lsimoneau 45581857,事实证明完全相同的事情正在发生。我只是通过附加区域选项将我的请求 URL 指向我存储桶上的区域,它就起作用了。

 const s3 = new AWS.S3(
 accessKeyId: config.awsAccessKeyID,
 secretAccessKey: config.awsSecretAccessKey,
 region: 'eu-west-2'  // add region here );

【讨论】:

【参考方案10】:

我们的团队偶尔会使用 Vue、axios 和 C# WebApi 看到这一点。在您尝试命中的端点上添加路由属性可以为我们修复它。

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

【讨论】:

我们不太确定为什么。哈哈。如果有人告诉我!【参考方案11】:

此错误的一个非常常见的原因可能是主机 API 已将请求映射到 http 方法(例如 PUT),而 API 客户端正在使用不同的 http 方法(例如 POST 或 GET)调用 API

【讨论】:

我在服务器中正确实现了 CORS,但我忘记添加 PUT 方法【参考方案12】:

禁用 chrome 安全性。创建 chrome 快捷方式 右键单击-> 属性-> 目标,粘贴此“C:\Program Files (x86)\Google\Chrome\Application\chrome.exe”--disable-web-security --user-data-dir="c:/ chromedev"

【讨论】:

【参考方案13】:

我认为从 Chrome 中禁用 CORS 不是好方法,因为如果您在 ionic 中使用它,肯定会在 Mobile Build 中再次出现问题。

最好在后端修复。

首先在header中,需要设置-

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

如果 API 的行为是 GET 和 POST ,那么也要在你的 header 中设置 -

if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') 如果 (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) 标头(“访问控制允许标头: $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']"); 退出(0);

【讨论】:

【参考方案14】:

GeoServer 的独立发行版包括 Jetty 应用服务器。启用跨域资源共享 (CORS) 允许您自己域之外的 javascript 应用程序使用 GeoServer。

从 webapps/geoserver/WEB-INF/web.xml 中取消注释以下 &lt;filter&gt;&lt;filter-mapping&gt;

<web-app>
  <filter>
      <filter-name>cross-origin</filter-name>
      <filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
  </filter>
  <filter-mapping>
      <filter-name>cross-origin</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

【讨论】:

这并没有在响应头中添加 antyhing,所以它没有工作 没有使用 GeoServer,但是这个剪辑帮助我了解了我应该在接收呼叫的应用程序上使用的设置。【参考方案15】:

php 中,您可以添加标题:

<?php
header ("Access-Control-Allow-Origin: *");
header ("Access-Control-Expose-Headers: Content-Length, X-JSON");
header ("Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS");
header ("Access-Control-Allow-Headers: *");
...

【讨论】:

谢谢,它对我有用!在测试和生产环境中。即使使用 https:// @atiruz 感谢您的解决方案。当我添加header ("Access-Control-Expose-Headers: Content-Length, X-JSON"); 行时,此方法有效【参考方案16】:

对于那些使用 Lambda 集成代理和 API 网关的用户。您需要像直接向其提交请求一样配置您的 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" : "*"
           
     

【讨论】:

我还想插话并提到一个我认为 AWS 文档中没有的大问题。假设您使用 API 网关代理您的 lambda 函数,并且您在该 lambda 函数中使用了一些 API。如果该 API 返回非 200 成功成功代码并且您没有将非 200 成功代码添加到 API 网关中的方法响应中,那么您将收到错误并且看不到您的成功响应。示例:Sendgrid 和 Twilio 的成功代码不是 200。【参考方案17】:

JavaScript XMLHttpRequestFetch 遵循同源策略。所以, 使用 XMLHttpRequest 或 Fetch 的 Web 应用程序只能使 HTTP 向自己的域发出请求。

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

您必须从服务器端发送 Access-Control-Allow-Origin: * HTTP 标头。

如果您使用 Apache 作为您的 HTTP 服务器,那么您可以将其添加到您的 Apache 配置文件中,如下所示:

<IfModule mod_headers.c>
    Header set Access-Control-Allow-Origin "*"
</IfModule>

在 Apache 中默认启用 Mod_headers,但是,您可能希望通过运行来确保它已启用:

 a2enmod headers

【讨论】:

在哪里可以找到我的 Apache 配置文件? @ShubhamArya on linux Debian 默认位置是:/etc/apache2/apache2.conf 在 windows 哪里可以找到它? @Shubham Arya:windows默认位置是C:\Program Files\Apache\Apache2\conf\httpd.conf,你可以在httpd.apache.org/docs/2.0/platform/windows.xml找到更多细节【参考方案18】:

如果您偶然使用 IIS 服务器。您可以在 HTTP 请求标头选项中设置以下标头。

Access-Control-Allow-Origin:*
Access-Control-Allow-Methods: 'HEAD, GET, POST, PUT, PATCH, DELETE'
Access-Control-Allow-Headers: 'Origin, Content-Type, X-Auth-Token';

所有的 post、get 等都可以正常工作。

【讨论】:

【参考方案19】:

很容易错过的东西……

在解决方案资源管理器中,右键单击 api-project。在属性窗口中将“匿名身份验证”设置为已启用!!!

【讨论】:

【参考方案20】:

在 AspNetCore web api 中,通过添加“Microsoft.AspNetCore.Cors”(版本 1.1.1)并在 Startup.cs 上添加以下更改来解决此问题。

public void ConfigureServices(IServiceCollection services)
 
    services.AddCors(options =>
    
          options.AddPolicy("AllowAllHeaders",
                builder =>
            
                    builder.AllowAnyOrigin()
                           .AllowAnyHeader()
                           .AllowAnyMethod();
                );
    );
    .
    .
    .

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)



    // Shows UseCors with named policy.
    app.UseCors("AllowAllHeaders");
    .
    .
    .

并将[EnableCors("AllowAllHeaders")] 放在控制器上。

【讨论】:

如果您想构建跨站点脚本漏洞,这是一个很好的答案!请永远不要这样做!指定您可以访问的域以避免安全问题。 CORS 的存在是有原因的。 只是为了更清楚@paqogomez,在您的 ConfigureServices 方法中: services.AddCors(options => options.AddPolicy("AllowSpecificOrigin", builder => builder.WithOrigins("localhost") .AllowAnyOrigin() .AllowAnyHeader() .AllowAnyMethod(); ); ); 并在您的配置方法中:app.UseCors("AllowSpecificOrigin");【参考方案21】:

在我的 Apache VirtualHost 配置文件中,我添加了以下几行:

Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header always set Access-Control-Max-Age "1000"
Header always set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, client-security-token"

RewriteEngine On
RewriteCond %REQUEST_METHOD OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]

【讨论】:

【参考方案22】:

当 DNS 服务器设置为 8.8.8.8(谷歌的)时,我遇到了这个问题。实际上,问题出在路由器上,我的应用程序试图通过谷歌连接服务器,而不是本地连接(对于我的特殊情况)。我已经删除了 8.8.8.8,这解决了这个问题。 我知道 CORS 设置解决了这个问题,但也许有人会遇到和我一样的麻烦

【讨论】:

【参考方案23】:

对于python flask server,可以使用flask-cors插件开启跨域请求。

见:https://flask-cors.readthedocs.io/en/latest/

【讨论】:

【参考方案24】:

我的“API 服务器”是一个 PHP 应用程序,所以为了解决这个问题,我找到了以下解决方案:

将行放在 index.php

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');

【讨论】:

我同意,这比公认的答案要好,尽管在复制这些行时要小心,请务必修改方法和来源。 在 Angular 6 项目中放在哪里? @CodyBugstein 和 whatthefish 放在任何输出之前 @whatthefish 这是服务器端更改,而不是客户端更改。 @AsmaRahimAliJafri 这必须在服务器端完成!

以上是关于对预检请求的响应未通过访问控制检查的主要内容,如果未能解决你的问题,请参考以下文章

对预检请求的响应未通过访问控制检查

对预检请求的响应未通过访问控制检查

对预检请求的响应未通过访问控制检查

为啥 CORS 错误“对预检请求的响应未通过访问控制检查”?

Express - 无法发送重定向,对预检请求的响应未通过访问控制检查

CORS:对预检请求的响应未通过访问控制检查:预检请求不允许重定向