虽然已经通过 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,它显示上述标头已成功传递:
https://i.stack.imgur.com/cowzz.png
从 OPTIONS 响应中:
https://i.stack.imgur.com/xRCeH.png
如何从浏览器调用我的 API 而不恢复为 JSON-P?
Bucket Policy
放上去吗?确保您的保单中有该方法
我遇到同样的问题。我已经用了 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-Gateway。
此外 - 如果您碰巧从通过 API Gateway 运行的请求中获得状态代码 0
或 1
,这可能是您的问题。
要修复 - 在 API 网关配置中 - 转到“网关响应”,展开“默认 4XX”并在那里添加 CORS 配置标头。 IE
Access-Control-Allow-Origin: '*'
确保重新部署您的网关 - 瞧!
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='"'"'*'"'"'
如果您尝试了有关此问题的所有方法均无济于事,那么您最终会遇到我所做的事情。事实证明,亚马逊现有的 CORS 设置说明工作得很好……只要确保你记得重新部署! CORS 编辑向导,即使带有所有漂亮的绿色小复选标记,也不会实时更新您的 API。也许很明显,但它困扰了我半天。
https://i.stack.imgur.com/pQnoi.png
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 密钥”选项。
让我的示例正常工作:我刚刚在生成的 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 以及您的请求以使其“不简单”并且预检将触发
不过,您必须自己为请求发送 CORS 标头,遵循 OPTIONS
把它们加起来:
API Gateway 只会自动生成无害的 OPTIONS
OPTIONS 仅被浏览器用作检查路径上 CORS 可能性的预防措施
是否接受 CORS 取决于实际方法,例如 GET / POST
您必须在响应中手动发送适当的标头
对我来说,最终有效的答案是来自 Alex R 的答案的 James Shapiro 的评论(第二个最受好评的)。我首先遇到了这个 API Gateway 问题,尝试获取托管在 S3 中的静态网页以使用 lambda 处理联系我们页面并发送电子邮件。只需检查 [ ] Default 4XX 即可修复错误消息。
https://i.stack.imgur.com/vYLwA.png
我在里面找到了一个简单的解决方案
API Gateway > 选择您的 API 端点 > 选择方法(在我的情况下是 POST)
现在有一个下拉菜单 ACTIONS > Enable CORS .. 选择它。
现在再次选择下拉操作 > 部署 API(重新部署它)
https://i.stack.imgur.com/JVAKq.png
有效 !
更改您的函数或代码之后 请按照以下两个步骤操作。
首先启用 CORS,然后每次部署 API。
在我意识到 lambda 授权程序失败并且由于某种未知原因被转换为 CORS 错误后,我开始工作。对我的授权人的一个简单修复(以及我应该首先添加的一些授权人测试)并且它有效。对我来说,API 网关操作“启用 CORS”是必需的。这在我的 API 中添加了我需要的所有标题和其他设置。
对我来说,因为我使用的是非常标准的 React fetch 调用,这可以使用上面的一些 AWS 控制台和 Lambda 修复来修复,但是我的 Lambda 返回了正确的标头(我也在使用代理模式)并且我需要打包我的应用程序到 SAM 模板中,所以我不能花时间在控制台周围点击。
我注意到所有 CORS 的东西都运行良好,直到我将 Cognito Auth 放到我的应用程序中。我基本上只是非常缓慢地使用越来越多的配置进行 SAM 包/SAM 部署,直到它坏了,并且在我将 Auth 添加到我的 API 网关后它就坏了。我花了一整天的时间点击类似这样的精彩讨论,寻找一个简单的解决方法,但最终不得不真正阅读 CORS 在做什么。我会保存你的阅读并给你另一个简单的修复(至少对我来说)。
以下是最终有效的 API Gateway 模板示例 (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,请尝试上面的修复。
在为 POST
和 OPTIONS
启用 CORS 后部署代码对我有用。
确保您调用的是正确的路径。
无论出于何种原因,点击不存在的路径都可能导致与 CORS 相关的错误。可能是因为 404
在其响应中不包含 CORS 标头。
感谢@jackko 对最初问题的评论。这是我的问题。听起来很傻,但可能发生在任何人身上。
我正在运行 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 Gateway 的授权方法,我需要授予我的 IAM 角色权限以访问端点。
就我而言,我启用了所有方法和网关响应。然后它就像一个魅力。不要忘记部署。
https://i.stack.imgur.com/a4FNU.png
对于 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 授权方,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
对于未来的患者:
这个被诅咒的问题再次困扰着我,这一次是因为我发送了一个自定义标头:
let headers = {
'Content-Type': 'application/json',
'Is-Web': true,
Authorization: `Bearer ${accessToken}`,
};
这个“Is-Web”自定义标头使 API Gateway 阻止了我的请求并将其屏蔽为 CORS 错误。如果您要发送一个,只需将其删除并进行测试。就因为这个,差点耽误了一整天的工作。
就我而言,我只是将获取请求 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。
在 Python 中,您可以按照以下代码执行此操作:
{ "statusCode" : 200,
'headers':
{'Content-Type': 'application/json',
'Access-Control-Allow-Origin': "*"
},
"body": json.dumps(
{
"temperature" : tempArray,
"time": timeArray
})
}
不定期副业成功案例分享