繁体   English   中英

API Gateway CORS:没有“Access-Control-Allow-Origin”标头

[英]API Gateway CORS: no 'Access-Control-Allow-Origin' header

虽然已经通过 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获取 URL,它显示上述标头已成功传递:

传递的标头

从 OPTIONS 响应中:

响应标头

如何从浏览器调用我的 API 而不恢复为 JSON-P?

我遇到同样的问题。 我已经用了 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);
};

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

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

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

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

Access-Control-Allow-Origin: '*'

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

如果您已经尝试了有关此问题的所有方法,但都无济于事,那么您最终会得到我所做的。 事实证明,亚马逊现有的 CORS 设置指导工作得很好……只要确保你记得重新部署 CORS 编辑向导,即使有所有漂亮的小绿色复选标记,也不会对您的 API 进行实时更新。 也许很明显,但它难倒了我半天。

在此处输入图片说明

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 网关 post 方法中禁用“API Key Required”选项。

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

这是我的 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(); }
});

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

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

对于 Google 员工:

原因如下:

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

把它们加起来:

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

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

在此处输入图片说明

我在里面找到了一个简单的解决方案

API 网关 > 选择您的 API 端点 > 选择方法(在我的情况下是 POST)

现在有一个下拉操作 > 启用 CORS .. 选择它。

现在再次选择下拉 ACTIONS > Deploy API(重新部署它)

在此处输入图片说明

有效 !

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

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

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

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

我正在运行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'"
#...

就我而言,由于我使用 AWS_IAM 作为 API 网关的授权方法,我需要授予我的 IAM 角色访问端点的权限。

对我来说,因为我使用的是非常标准的 React fetch 调用,所以这可以使用上面的一些 AWS 控制台和 Lambda 修复来修复,但是我的 Lambda 返回了正确的标头(我也使用了代理模式),我需要打包我的应用程序升级到 SAM 模板,所以我不能花时间在控制台上单击。

我注意到所有 CORS 的东西都运行良好,直到我将 Cognito Auth 放到我的应用程序中。 我只是在使用越来越多的配置进行 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 需要身份验证,但如果您的 OPTIONS 启用了身份验证,那么您可能会发现自己处于这种情况。 如果您在 AWS 控制台周围单击,请尝试从 OPTIONS 中删除,重新部署,然后进行测试。 如果您使用的是 SAM CLI,请尝试我上面的修复。

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

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

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

对于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);
}

此问题的另一个根本原因可能是 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标头时检查区分大小写。

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

执行“启用 CORS”操作只会设置 200 个状态。 如果您在端点上有其他人,例如 4xx 和 5xx,您需要自己添加标头。

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

在此处输入图片说明

对于在 API Gateway 中使用 Cognito 授权器的用户,实际上无需设置自定义网关响应。 API 网关会阻止预检,因为它们在默认的 AWS 逻辑中是“未经授权的”。

幸运的是,有一个内置参数可以解决这个问题。 只需将AddDefaultAuthorizerToCorsPreflight: False添加到您的 API Authorizer,API Gateway 将禁用预检请求的身份验证。 这是文档和示例设置:

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

对于未来的患者:

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

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

这个“Is-Web”自定义标头使 API Gateway 阻止了我的请求并将其屏蔽为 CORS 错误。 如果您要发送一个,只需将其删除并测试即可。 几乎因此失去了一整天的工作。

我已经有这个问题很长一段时间了。 我最终把它放到我的 python lambda 函数中

 response ={
        'statusCode': statusCode,
        'headers':{
             'Access-Control-Allow-Headers': 'Content-Type',
             'Access-Control-Allow-Origin': '*',
             'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
                  },
                  'body':json.dumps(body)
              }
    return response 

我希望这可以帮助那里的人

就我而言,我只是将获取请求 URL 写错了。 serverless.yml ,你设置corstrue

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。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM