API 网关 CORS: 没有“访问控制-允许-起源”头

虽然 CORS 已经通过 API Gateway 设置好了,Access-Control-Allow-Origin头部也设置好了,但是当我试图在 Chrome 中从 AJAX 调用这个 API 时,仍然会收到以下错误:

XMLHttpRequest 无法加载 http://XXXXX.execute-api.us-west-2.amazonaws.com/beta/YYYYY。请求的资源上没有“访问控制-允许-起源”标头。因此,不允许访问原始文件‘ null’。反应 HTTP状态码为403。

我尝试通过 邮差获取 URL,结果显示上面的头文件已经成功传递:

Passed headers

从期权的反应来看:

Response headers

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

181922 次浏览

我也有同样的问题,我花了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);
};

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 网关配置上使用 lambda 函数的代理时,post 或 get 方法没有添加头,只有选项有。您必须在响应(服务器或 lambda 响应)中手动执行此操作。

3)及

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

让我的示例工作起来: 我在生成的 nodejsLambda 函数中将 “访问-控制-允许-起源”: “ *”,插入到 标题: {}中。我对 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(); }
});

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

如果您正在运行 API-Gateway 与自定义的授权者-API-Gateway 将发送一个401或403返回之前,它实际上到达您的服务器。默认情况下-API-当从自定义授权程序返回4xx 时,网关没有为 CORS 配置。

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

要修复-在 API 网关配置-转到“网关响应”,展开“默认4XX”并在那里添加一个 CORS 配置头。也就是说。

Access-Control-Allow-Origin: '*'

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

在我意识到 lambda 授权程序失败并且由于某种未知的原因被转换为 CORS 错误之后,我让我的程序工作了起来。对我的授权者进行一个简单的修复(以及一些我应该在第一时间添加的授权者测试) ,它就起作用了。对我来说,API 网关操作“启用 CORS”是必需的。这添加了我在 API 中需要的所有头部和其他设置。

如果你已经尝试了所有关于这个问题的方法,但是没有用,那么你就会像我一样。事实证明,亚马逊现有的 CORS 设置方向工作得很好... 只要确保你 记得重新部署!CORS 编辑向导,即使有它所有漂亮的绿色小复选标记,也不会对您的 API 进行实时更新。也许是显而易见的,但这让我困惑了半天。

enter image description here

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

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

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

在我的例子中,我只是写错了获取请求的 URL:

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。

在我的例子中,因为我使用 AWS _ IAM 作为 API 网关的授权方法,所以我需要授予我的 IAM 角色权限来访问端点。

这个问题的另一个根本原因可能是 HTTP/1.1和 HTTP/2之间的区别。

症状: 一些用户,不是所有的用户,在使用我们的软件时报告得到 CORS 错误。

问题: Access-Control-Allow-Origin头部缺少 有时候

上下文: 我们有一个 Lambda,专门用于处理 OPTIONS请求并使用相应的 CORS 报头进行响应,例如与白名单中的 Origin匹配的 Access-Control-Allow-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报头时检查大小写敏感性。

我找到了一个简单的解决办法

API Gateway > Select your API endpoint > Select the method (在我的例子中是 POST)

现在有一个下拉菜单 ACTION > Enable CORS. . select it。

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

enter image description here

成功了!

在 Python 中,你可以按照下面的代码来做:

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

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

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

对于谷歌员工:

原因如下:

  • 简单的请求,或者没有 cookie 的 GET/POST不会触发起飞前
  • 当您为路径配置 CORS 时,API 网关只会为该路径创建一个 OPTIONS方法,然后在用户调用 OPTIONS时使用模拟响应发送 Allow-Origin报头,但是 GET/POST不会自动获得 Allow-Origin
  • 如果您尝试使用 CORS 模式发送简单请求,您将得到一个错误,因为该响应没有 Allow-Origin
  • 您可能会遵循最佳实践,简单的请求并不意味着向用户发送响应,将身份验证/cookie 与您的请求一起发送以使其“不简单”,并且会触发起飞前的请求
  • 不过,您必须自己为 OPTIONS之后的请求发送 CORS 头

总结一下:

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

更改函数或代码后,请执行以下两个步骤。

先是 启动 CORS然后每次都是 部署 API

在为 POSTOPTIONS启用 CORS 之后部署代码对我来说很有用。

我只是在我的 lambda 函数响应中添加了标题,它的工作效果非常好

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

对我来说,最终起作用的答案是詹姆斯 · 夏皮罗对亚历克斯 · R 的回答的评论(第二多的反对者)。我首先遇到了这个 API 网关问题,通过尝试获得一个驻留在 S3中的静态网页,使用 lambda 来处理联系人页面并发送电子邮件。只需检查[] Default 4XX 即可修复错误消息。

enter image description here

对我来说,由于我使用的是相当标准的 React 提取调用,这可以通过上面的一些 AWS Console 和 Lambda 修复来修复,但是我的 Lambda 返回了正确的头(我也使用代理模式) ,我需要将我的应用程序打包成 SAM 模板,这样我就不能花时间在控制台上点击。

我注意到,所有的 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 时,它会阻止正常的 OPTION 行为,以宣布资源根据允许的起源支持什么。一旦我明确地添加了它并将其设置为 False,所有问题都得到了解决。

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

在我的例子中,我启用了所有的方法和网关响应。然后就成功了。别忘了部署。

enter image description here

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

碰到一个不存在的路径,可能会导致 CORS 相关的错误,不管是什么原因。可能是因为 404在响应中没有包括 CORS 头。

感谢@jackko 对第一个问题的评论。这是我的问题。听起来很傻,但是任何人都可能遇到。

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

幸运的是,有一个内置的参数来解决这个问题。只需将 AddDefaultAuthorizerToCorsPreflight: False添加到您的 API Authorizer 和 API 网关将禁用飞行前请求的身份验证。下面是 文件,以及一个示例设置:

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

对于 巨蟒,如@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);
}

对于未来的患者:

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

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

这个“ Is-Web”自定义头使 API 网关阻止我的请求,并将其掩盖为 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

我希望这能帮到别人