【问题标题】:API Gateway CORS: no 'Access-Control-Allow-Origin' headerAPI Gateway CORS:没有“Access-Control-Allow-Origin”标头
【发布时间】:2016-05-13 10:49:04
【问题描述】:

虽然已经通过 API Gateway 设置了 CORS 并且设置了 Access-Control-Allow-Origin 标头,但在 Chrome 中尝试从 AJAX 调用 API 时仍然收到以下错误:

XMLHttpRequest 无法加载 http://XXXXX.execute-api.us-west-2.amazonaws.com/beta/YYYYY。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,Origin 'null' 不允许访问。响应的 HTTP 状态代码为 403。

我尝试通过Postman 获取网址,显示上述标头已成功传递:

并且来自 OPTIONS 响应:

如何在不恢复为 JSON-P 的情况下从浏览器调用我的 API?

【问题讨论】:

  • 你在 S3 上设置了吗?如果是这样,您可以提出Bucket Policy 吗?确保您的策略中有该方法
  • API Gateway 团队在这里... 如果您在控制台中使用“启用 CORS”功能,则配置应该是正确的。我最好的猜测是您没有在浏览器正在执行的 JavaScript 中调用 API 中的正确资源路径。如果您尝试对不存在的方法/资源/阶段进行 API 调用,您将收到没有任何 CORS 标头的通用 403。如果您调用正确的资源,我看不到浏览器如何错过 Access-Control-Allow-Origin 标头,因为 Postman 中的 OPTIONS 调用清楚地包含所有正确的 CORS 标头。
  • @RyanG-AWS 客户端没有对请求进行签名,因为 API 是由它使用用户特定令牌调用的资源进行身份验证的,因此凭证不是一个因素。我可以通过直接在浏览器中访问 URL 来调用 API,并得到相应的响应。
  • @makinbacon:你找到解决方案了吗?我在这里遇到了同样的问题。
  • 我的方法和阶段是由 Lambda 自动生成的。事后我启用了 CORS。与 OP 相同的错误。我吹走了自动生成的东西,创建了一个新的 API 和方法,部署到一个新的阶段,它工作得很好。

标签: ajax amazon-web-services cors aws-api-gateway


【解决方案1】:

我遇到了同样的问题。我已经用了 10 个小时来找出答案。

https://serverless.com/framework/docs/providers/aws/events/apigateway/

// handler.js

'use strict';

module.exports.hello = function(event, context, callback) {

const response = {
  statusCode: 200,
  headers: {
    "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
    "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS 
  },
  body: JSON.stringify({ "message": "Hello World!" })
};

callback(null, response);
};

【讨论】:

  • 修复了我遇到的问题。谢谢你的回答!
  • 仅供参考,此处提供的示例存在问题。如果您有“Access-Control-Allow-Credentials”:true,则不能将通配符 * 用于 Access-Control-Allow-Origin。此规则由浏览器强制执行。见herehere
  • 这不起作用,再次显示相同的错误 Request header field access-control-allow-credentials is not allowed by Access-Control-Allow-Headers in preflight response.
  • 对于任何好奇的人,这里是提到这一点的官方文档:docs.aws.amazon.com/apigateway/latest/developerguide/… > 对于 Lambda 或 HTTP 代理集成,您仍然可以在 API 网关中设置所需的 > OPTIONS 响应标头。但是,您必须依靠 > 后端返回 Access-Control-Allow-Origin 标头,因为代理集成禁用了 > 集成响应。
  • 只设置 "Access-Control-Allow-Origin" : "*" from lambda 解决了这个问题
【解决方案2】:

1) 我需要做与@riseres 相同的操作和其他一些更改。这是我的响应标头:

headers: {
            'Access-Control-Allow-Origin' : '*',
            'Access-Control-Allow-Headers':'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token',
            'Access-Control-Allow-Credentials' : true,
            'Content-Type': 'application/json'
        }

2) 和

根据本文档:

http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html

当您在 API Gateway 配置中为 lambda 函数使用代理时,post 或 get 方法没有添加标头,只有选项有。您必须在响应(服务器或 lambda 响应)中手动执行。

3) 和

除此之外,我需要在我的 API 网关发布方法中禁用“需要 API 密钥”选项。

【讨论】:

  • 是的,我认为我们很多人最初错过的微妙之处是,一旦您使用“使用 Lambda 代理集成”为 Lambda 函数配置 API 网关集成,那么您必须像您和其他人一样做正在声明并确保以编程方式将标头添加到您的 lambda 响应中。通过 API 网关上的“启用 CORS”创建的自动生成内容并创建一个 OPTIONS 响应程序非常棒,但如果您在 API 内的集成请求中设置“使用 Lambda 代理集成”,则不会让您一路走好网关。
  • 这对我有用...正确阅读手册后:重要提示将上述说明应用于代理集成中的 ANY 方法时,将不会设置任何适用的 CORS 标头。相反,您的后端必须返回适用的 CORS 标头,例如 Access-Control-Allow-Origin。 docs.aws.amazon.com/apigateway/latest/developerguide/…
【解决方案3】:

让我的示例正常工作:我刚刚headers:{} 中插入了 'Access-Control-Allow-Origin': '*', > 在生成的 nodejs Lambda 函数中。我对 Lambda 生成的 API 层进行了no更改。

这是我的 NodeJS:

'use strict';
const doc = require('dynamodb-doc');
const dynamo = new doc.DynamoDB();
exports.handler = ( event, context, callback ) => {
    const done = ( err, res ) => callback( null, {
        statusCode: err ? '400' : '200',
        body: err ? err.message : JSON.stringify(res),
        headers:{ 'Access-Control-Allow-Origin' : '*' },
    });
    switch( event.httpMethod ) {
        ...
    }
};

这是我的 AJAX 调用

$.ajax({
    url: 'https://x.execute-api.x-x-x.amazonaws.com/prod/fnXx?TableName=x',
    type: 'GET',
    beforeSend: function(){ $( '#loader' ).show();},
    success: function( res ) { alert( JSON.stringify(res) ); },
    error:function(e){ alert('Lambda returned error\n\n' + e.responseText); },
    complete:function(){ $('#loader').hide(); }
});

【讨论】:

  • 我发现很多亚马逊的文档已经过时,即使是“../latest/..”路径片段。在大约一周前报废所有东西后,CORS 按钮突然表示工作正常。 API 自动创建了“ANY”方法,CORS 按钮自动创建了“OPTIONS”方法——我没有向 API 添加任何内容。上面的“GET”可以工作,我已经添加了一个 ajax“POST”,它也可以在我不接触 API 的情况下工作。
  • 我花了将近两个小时试图弄清楚如何使用 AWS 控制台将 Access-Control-Allow-Origin 添加到方法响应中,但这也是唯一对我有用的方法。
【解决方案4】:

如果还有其他人遇到这种情况 - 我能够在我的应用程序中找到根本原因。

如果您使用自定义授权器运行 API-Gateway - API-Gateway 将在实际访问您的服务器之前发送回 401 或 403。默认情况下 - 从自定义授权方返回 4xx 时,未为 CORS 配置 API-Gateway。

另外 - 如果您碰巧从通过 API 网关运行的请求中获得状态代码 01,这可能是您的问题。

要修复 - 在 API 网关配置中 - 转到“网关响应”,展开“默认 4XX”并在那里添加 CORS 配置标头。即

Access-Control-Allow-Origin: '*'

确保重新部署您的网关 - 瞧!

【讨论】:

  • 对于那些想要使用 AWS CLI 执行此操作的用户,请使用:aws apigateway update-gateway-response --rest-api-id "XXXXXXXXX" --response-type "DEFAULT_4XX" --patch-operations op="add",path="/responseParameters/gatewayresponse.header.Access-Control-Allow-Origin",value='"'"'*'"'"'
  • 给我自己的注意 - 之后不要忘记部署 API :)
  • 奇怪,这对我有用,但我不必重新部署。我之前确实尝试过重新部署。不知道为什么它对我有用。
  • 将 CORS 标头添加到 4XX 可以让您看到实际的错误消息,而不是 CORS 错误。
  • 仅供参考,从 AWS 控制台执行此操作的方法是单击方法(即“POST”然后“启用 CORS”,然后检查 4XX 选项,然后部署。
【解决方案5】:

在我意识到 lambda 授权程序失败并且由于某种未知原因被转换为 CORS 错误后,我开始工作。对我的授权人的一个简单修复(以及我应该首先添加的一些授权人测试)并且它有效。对我来说,API 网关操作“启用 CORS”是必需的。这在我的 API 中添加了我需要的所有标题和其他设置。

【讨论】:

  • 并重新部署! :)
【解决方案6】:

如果您尝试了有关此问题的所有方法都无济于事,那么您最终会遇到我所做的事情。事实证明,Amazon 现有的 CORS 设置说明可以正常工作……只要确保您记得重新部署! CORS 编辑向导,即使带有所有漂亮的绿色小复选标记,也不会对您的 API 进行实时更新。也许很明显,但它困扰了我半天。

【讨论】:

  • 就是这样。从字面上看这两天。不确定编辑网关后至少不提示重新部署的逻辑。
  • @ChrisChristensen 很高兴你弄明白了 - 总有一些东西让你解脱,却又令人难以置信地挫败这样的问题
  • 这是2020年有效的答案。谢谢
  • 重新部署重新部署重新部署
  • 我在任何地方都找不到这个菜单。我怀疑其中许多解决方案是针对 REST api,而不是 HTTP api。
【解决方案7】:

我正在运行aws-serverless-express,在我的情况下需要编辑simple-proxy-api.yaml

在将 CORS 配置为 https://example.com 之前,我只是交换了我的站点名称并通过 npm run setup 重新部署,它更新了我现有的 lambda/stack。

#...
/:
#...
method.response.header.Access-Control-Allow-Origin: "'https://example.com'"
#...
/{proxy+}:
method.response.header.Access-Control-Allow-Origin: "'https://example.com'"
#...

【讨论】:

    【解决方案8】:

    就我而言,我只是将获取请求 URL 写错了。在serverless.yml 上,您将cors 设置为true

    register-downloadable-client:
        handler: fetch-downloadable-client-data/register.register
        events:
          - http:
              path: register-downloadable-client
              method: post
              integration: lambda
              cors: true
              stage: ${self:custom.stage}
    

    然后在 lambda 处理程序上发送标头,但如果您在前端使获取请求错误,您将不会在响应中获得该标头,并且您将收到此错误。因此,请仔细检查前面的请求 URL。

    【讨论】:

      【解决方案9】:

      在我的例子中,由于我使用 AWS_IAM 作为 API Gateway 的授权方法,我需要授予我的 IAM 角色访问端点的权限。

      【讨论】:

      • 我很高兴我留下了这条评论。这一直发生在我身上:D。
      • 我喜欢为未来反复出现的问题找到自己的解决方案。
      【解决方案10】:

      此问题的另一个根本原因可能是 HTTP/1.1 和 HTTP/2 之间的差异。

      症状:部分用户(并非全部)报告在使用我们的软件时遇到 CORS 错误。

      问题:Access-Control-Allow-Origin 标头丢失有时

      上下文:我们有一个 Lambda,专用于处理 OPTIONS 请求并使用相应的 CORS 标头进行回复,例如 Access-Control-Allow-Origin 匹配列入白名单的 Origin

      解决方案: API 网关似乎将所有标头转换为 HTTP/2 调用的小写,但保持 HTTP/1.1 的大写。这导致对event.headers.origin 的访问失败。

      检查您是否也遇到此问题:

      假设您的 API 位于 https://api.example.com,而您的前端位于 https://www.example.com。使用 CURL,使用 HTTP/2 发出请求:

      curl -v -X OPTIONS -H 'Origin: https://www.example.com' https://api.example.com
      

      响应输出应包含标头:

      < Access-Control-Allow-Origin: https://www.example.com

      使用 HTTP/1.1(或使用小写的 Origin 标头)重复相同的步骤:

      curl -v -X OPTIONS --http1.1 -H 'Origin: https://www.example.com' https://api.example.com
      

      如果缺少Access-Control-Allow-Origin 标头,您可能需要在读取Origin 标头时检查是否区分大小写。

      【讨论】:

        【解决方案11】:

        我在

        中找到了一个简单的解决方案

        API Gateway > 选择您的 API 端点 > 选择方法(在我的例子中是 POST)

        现在有一个下拉菜单 ACTIONS > Enable CORS .. 选择它。

        现在再次选择下拉菜单操作 > 部署 API(重新部署)

        成功了!

        【讨论】:

        • 为什么这个答案被否决了,但下面还有其他类似的答案?
        • 对于基于 AWS 的 API 网关调用,此解决方案有效
        【解决方案12】:

        在 Python 中,您可以按照以下代码进行操作:

        { "statusCode" : 200,
        'headers': 
            {'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': "*"
             },
        "body": json.dumps(
            {
            "temperature" : tempArray,
            "time": timeArray
            })
         }
        

        【讨论】:

          【解决方案13】:

          除了其他 cmets,需要注意的是从底层集成返回的状态,以及是否为该状态返回了 Access-Control-Allow-Origin 标头。

          执行“启用 CORS”仅设置 200 状态。如果端点上有其他的,例如 4xx 和 5xx,则需要自己添加 header。

          【讨论】:

            【解决方案14】:

            对于 Google 员工:

            原因如下:

            • 简单的请求,或者,没有 cookie 的 GET/POST 不会触发预检
            • 当您为路径配置 CORS 时,API Gateway 只会为该路径创建一个 OPTIONS 方法,然后在用户调用 OPTIONS 时使用模拟响应发送 Allow-Origin 标头,但 GET / POST 将不会自动获取Allow-Origin
            • 如果您尝试在 CORS 模式开启的情况下发送简单请求,则会收到错误消息,因为该响应没有 Allow-Origin 标头
            • 您可以坚持最佳实践,简单的请求并不意味着向用户发送响应,发送身份验证/cookie 以及您的请求以使其“不简单”并且预检将触发
            • 不过,对于OPTIONS 之后的请求,您必须自己发送 CORS 标头

            总结一下:

            • API 网关会自动生成无害的OPTIONS
            • OPTIONS 仅被浏览器用作一种预防措施来检查路径上 CORS 的可能性
            • 是否接受 CORS 取决于实际方法,例如GET / POST
            • 您必须在响应中手动发送适当的标头

            【讨论】:

              【解决方案15】:

              更改您的函数或代码后请按照以下两个步骤操作。

              首先启用 CORS,然后每次部署 API

              【讨论】:

              • 谢谢你。没有注意到资源中的“启用 CORS”。让我失去理智。
              • 这条评论拯救了我的一天!我不知道每次更改“启用 CORS”时都必须“部署 API”
              【解决方案16】:

              在为 POSTOPTIONS 启用 CORS 后部署代码对我有用。

              【讨论】:

              • 感谢您的贡献,但是您能解释一下为什么它对您有用吗?我邀请您阅读本指南以改进您的答案:“我如何写一个好的答案”:stackoverflow.com/help/how-to-answer
              【解决方案17】:

              我刚刚在我的 lambda 函数响应中添加了标题,它就像一个魅力

              exports.handler = async (event) => {
                  const response = {
                      statusCode: 200,
                      body: JSON.stringify('Hey it works'),
                      headers:{ 'Access-Control-Allow-Origin' : '*' }
                  };
                  return response;
              };
              

              【讨论】:

                【解决方案18】:

                对我来说,最终有效的答案是来自 Alex R 的答案的 James Shapiro 的评论(第二个最受好评的)。我首先遇到了这个 API Gateway 问题,尝试获取托管在 S3 中的静态网页以使用 lambda 处理联系我们页面并发送电子邮件。只需检查 [ ] Default 4XX 即可修复错误消息。

                【讨论】:

                • 你在哪里可以找到这个菜单?我在任何地方都没有看到它。
                • @NickH 看看 Ravi Ram 的照片。在“Actions”下,应该有一个名为“Enable CORS”的项目,当你选择它时,菜单就会出现。
                【解决方案19】:

                对我来说,由于我使用的是非常标准的 React fetch 调用,因此可以使用上面的一些 AWS 控制台和 Lambda 修复程序来解决这个问题,但是我的 Lambda 返回了正确的标头(我也在使用代理模式)并且我需要将我的应用程序打包到一个 SAM 模板中,这样我就不能花时间在控制台周围点击。

                我注意到在我将 Cognito Auth 放入我的应用程序之前,所有的 CORS 东西都运行良好。我基本上只是在使用越来越多的配置进行 SAM 包/SAM 部署时非常缓慢,直到它崩溃,并且在我将 Auth 添加到我的 API 网关后它就崩溃了。我花了一整天的时间点击像这样的精彩讨论,寻找一个简单的解决方法,但最终不得不真正阅读 CORS 在做什么。我会保存你的阅读并给你另一个简单的修复(至少对我来说)。

                这里是一个 API 网关模板的示例,最终可以正常工作 (YAML):

                Resources:
                  MySearchApi:
                    Type: AWS::Serverless::Api
                    Properties:
                      StageName: 'Dev'
                      Cors:
                        AllowMethods: "'OPTIONS, GET'"
                        AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
                        AllowOrigin: "'*'"
                      Auth:
                        DefaultAuthorizer: MyCognitoSearchAuth
                        Authorizers:
                          MyCognitoSearchAuth:
                            UserPoolArn: "<my hardcoded user pool ARN>"
                            AuthType: "COGNITO_USER_POOLS"
                        AddDefaultAuthorizerToCorsPreflight: False
                

                注意底部的 AddDefaultAuthorizerToCorsPreflight。据我从阅读中得知,如果您的模板中没有它,则默认为 True。并且,当为 True 时,它​​会阻止正常的 OPTIONS 行为,以宣布资源在允许的来源方面支持的内容。一旦我明确添加它并将其设置为 False,我的所有问题都已解决。

                这意味着如果您遇到此问题并希望更全面地诊断它,您应该访问 API Gateway 中的资源并检查您的 OPTIONS 方法是否包含某种形式的身份验证。您的 GET 或 POST 需要 Auth,但如果您的 OPTIONS 启用了 Auth,那么您可能会发现自己处于这种情况。如果您在 AWS 控制台周围单击,请尝试从 OPTIONS 中删除,重新部署,然后进行测试。如果您使用的是 SAM CLI,请尝试上面的修复。

                【讨论】:

                  【解决方案20】:

                  就我而言,我启用了所有方法和网关响应。然后它就像一个魅力。不要忘记部署。

                  【讨论】:

                  • 我也遇到过这个错误。在您的 lambda 级别(例如,如果您使用代理 [API 网关 -> lambda])以及在 api 网关启用日志记录以了解问题发生的位置,这一点很重要。就我而言,我没有为 CORS 启用 4xx 或 5xx,我必须检查 lambda cloudwatch 日志以了解错误发生的位置。
                  【解决方案21】:

                  确保您调用的是正确的路径。

                  点击不存在的路径,无论出于何种原因,都可能导致与 CORS 相关的错误。可能是因为404 在其响应中不包含 CORS 标头。

                  感谢@jackko 对最初问题的评论。这是我的问题。听起来很傻,但可能发生在任何人身上。

                  【讨论】:

                  • 看到这条评论后,我检查了我的网址。啊!这确实是我的 URL 的问题。由于我收到了 CORS 错误,因此添加了一个额外的 '/' 参数。这条评论真的救了我!非常感谢您指出这一点!
                  【解决方案22】:

                  对于那些在 API 网关中使用 Cognito 授权方的用户,实际上不需要设置自定义网关响应。 API 网关会阻止飞行前,因为默认情况下它们是“未经授权”的 AWS 逻辑。

                  幸运的是,有一个内置参数可以解决此问题。只需将AddDefaultAuthorizerToCorsPreflight: False 添加到您的 API 授权方,API 网关就会禁用飞行前请求的身份验证。这是documentation,以及一个示例设置:

                  MyApi:
                  Type: AWS::Serverless::Api
                  Properties:
                    StageName: Prod
                    Cors: 
                      AllowHeaders: "'*'"
                      AllowMethods: "'*'"
                      AllowOrigin: "'*'"
                    Auth:
                      DefaultAuthorizer: MyCognitoAuthorizer
                      AddDefaultAuthorizerToCorsPreflight: False
                      Authorizers:
                        MyCognitoAuthorizer:
                          UserPoolArn: !GetAtt MyCognitoUserPool.Arn
                  

                  【讨论】:

                    【解决方案23】:

                    对于Python,正如@riseres 提到的,在导入json 等之后...

                    // lambda handler
                    
                    def hello(event, context, callback):
                    response = {
                      statusCode: 200,
                      headers: {
                        "Access-Control-Allow-Origin" : "*", # Required for CORS support, to work, also you should instead specify the proper origin if credentials are mandatory
                        "Access-Control-Allow-Credentials" : True # Required for cookies, authorization headers with HTTPS 
                      },
                      body: json.dumps({ "message": "Hello World!" })
                    }
                    
                    callback(null, response);
                    }
                    

                    【讨论】:

                      【解决方案24】:

                      对于未来的患者:

                      这个被诅咒的问题再次困扰着我,这一次是因为我发送了一个自定义标头:

                      let headers = {
                        'Content-Type': 'application/json',
                        'Is-Web': true,
                        Authorization: `Bearer ${accessToken}`,
                      };
                      

                      这个“Is-Web”自定义标头使 API Gateway 阻止了我的请求并将其掩盖为 CORS 错误。如果您要发送一个,只需将其删除并进行测试。因为这个,差点丢了一整天的工作。

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2018-08-30
                        • 2018-09-19
                        • 2019-06-19
                        • 2017-04-15
                        • 2014-01-20
                        • 2019-02-07
                        • 2016-01-21
                        • 1970-01-01
                        相关资源
                        最近更新 更多