API网关CORS:无“ Access-Control-Allow-Origin”标头


102

尽管已通过API网关设置了CORS并设置了Access-Control-Allow-Origin标头,但尝试从Chrome中的AJAX调用API时,我仍然收到以下错误:

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

我试图通过邮递员获取URL ,它显示上述标题已成功传递:

传递的标题

从选项响应中:

响应头

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


您在S3上安装了它吗?如果是这样,您能忍受Bucket Policy吗?确保您的策略中有该方法
iSkore 2016年

10
这里的API网关团队...如果您在控制台中使用“启用CORS”功能,则配置应该正确。我最好的猜测是您没有在浏览器正在执行的JavaScript中的API中调用正确的资源路径。如果您尝试对不存在的方法/资源/阶段进行API调用,则会收到不带CORS标头的通用403。如果您调用正确的资源,我看不到浏览器怎么会错过Access-Control-Allow-Origin标头,因为Postman中的OPTIONS调用显然包含所有正确的CORS标头。
jackko '02

1
@ RyanG-AWS客户端未对请求进行签名,因为该API通过使用特定于用户的令牌调用的资源进行了身份验证,因此凭据不是一个因素。我可以通过直接在浏览器中访问URL来调用API,并得到适当的响应。
泰勒(Tyler)

2
@makinbacon:您找到了解决方案吗?我在这里遇到同样的问题。
Nirmal

1
我的方法和阶段是由Lambda自动生成的。事后我启用了CORS。与OP相同的错误。我吹走了自动生成的内容,创建了新的API和方法,部署到了新的阶段,并且运行良好。
烫伤

Answers:


116

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

修复了我也遇到的问题。谢谢您的回答!
埃里克·布朗

我不使用无服务器,但这解决了我的问题。猜猜您需要将这些标头从实际源中传递出去。
哥斯达黎加

2
仅供参考,此处提供的示例存在问题。如果您具有“ Access-Control-Allow-Credentials”:true,则不能为Access-Control-Allow-Origin使用通配符*。该规则由浏览器强制执行。看到这里这里
Kevin

1
这是行不通的,再次显示相同的错误在飞行前响应中,Access-Control-Allow-Headers不允许请求标头字段access-control-allow-credentials。
mitesh7172

如何使用java RequestHandler <RequestClass,ResponseClass>类做到这一点?
Snedden27 '19

104

如果还有其他人陷入困境-我能够在我的应用程序中找到根本原因。

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

另外-如果您碰巧从API网关运行的请求中获取状态代码01从中获取状态代码,则可能是您遇到的问题。

要解决-在API网关配置中-转到“网关响应”,展开“默认4XX”,然后在其中添加CORS配置标头。即

Access-Control-Allow-Origin: '*'

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


7
我爱你。认真地为此工作了两天。
efong5

4
对于那些希望通过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='"'"'*'"'"'

1
我没有使用自定义授权者,但仍然需要它,因为我的请求中包含错误的JSON-谢谢!
Force Hero

9
提醒

2
奇怪,这对我有用,但是我不必重新部署。我确实曾尝试过重新部署。不知道为什么对我有用。
迈克尔

19

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

3)并且

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


5
是的,我认为我们很多人最初遗漏的微妙之处是,一旦使用“使用Lambda代理集成”为Lambda函数配置了API网关集成,那么您就必须照做,并确保其他人声明并添加标头以编程方式显示在您的lambda响应中。通过在API网关上“启用CORS”创建并创建OPTIONS响应器的自动生成的东西很棒,但是如果您在API的“集成请求”中设置“使用Lambda代理集成”,则无法一路实现网关。

1
这对我有用...在正确阅读手册之后:重要说明:将以上说明应用于代理集成中的ANY方法时,将不会设置任何适用的CORS标头。相反,您的后端必须返回适用的CORS标头,例如Access-Control-Allow-Origin。 docs.aws.amazon.com/apigateway/latest/developerguide/…–
BennyHilarious

14

如果您对这个问题的所有尝试都无济于事,那么您将以我所做的一切而告终。事实证明,亚马逊现有的CORS设置说明工作正常……只要确保您记得重新部署即可!CORS编辑向导,即使带有所有漂亮的绿色小标记,也不会实时更新您的API。也许很明显,但是它让我难过了半天。

在此处输入图片说明


就是这样 从字面上看这工作了两天。在编辑网关后,至少在不提示重新部署的逻辑上不确定。
克里斯·克里斯滕森

@ChrisChristensen高兴你想通弄明白了-总有一些这样缓解但令人难以置信的击败关于这样的问题
激射

这是在2020年有效的答案。谢谢
Rahul Khanna

重新部署重新部署
Surjith SM

11

得到了我的样品工作:我插入的“访问控制允许来源”:“*”,里面标题:{}在生成的LAMBDA的NodeJS功能。我没有对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(); }
});

我发现许多Amazon文档都是过时的,即使使用了“ ../latest/ ..”路径片段也是如此。在大约一周前报废了所有内容之后,CORS按钮突然显示工作正常。API会自动创建“ ANY”方法,CORS按钮会自动创建“ OPTIONS”方法-我没有向API添加任何内容。上面的“ GET”有效,并且自此以后,我添加了一个ajax“ POST”,即使我不触摸API也可以使用。
MannyC '17

我花了近两个小时试图弄清楚如何使用AWS控制台将Access-Control-Allow-Origin添加到方法响应中,但这也是唯一对我有用的方法。
Shn_Android_Dev '19

8

对于Google员工:

原因如下:

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

把它们加起来:

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

5

我只是在我的lambda函数响应中添加了标头,它的工作原理就像一个魅力

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

4

我发现一个简单的解决方案

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

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

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

在此处输入图片说明

有效 !


为什么这个答案不正确,但是下面还有其他类似的答案?
Dinesh Kumar

对于基于AWS的API网关调用,此解决方案有效
ewalel

3

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


然后重新部署!:)
罗宾·C·塞缪尔



2

对我而言,最终可行的答案是Alex R的答案中James Shapiro的评论(第二高的评价)。首先,我试图通过在S3中托管一个静态网页来使用lambda处理与我们联系的页面并发送电子邮件来解决这个API网关问题。只需检查[]默认4XX,即可修复错误消息。

在此处输入图片说明


您在哪里找到此菜单?我什么都看不到。
Nick H

@NickH看看Ravi Ram的照片。在“操作”下,应该有一个名为“启用CORS”的项目,选择该项目后,将显示菜单。
杰森

1

我正在跑步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'"
#...

1

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


2
老兄,我很高兴我留下了这一评论。这一直在我身上发生:D。
CamHart

我喜欢为以后出现的问题找到自己的解决方案。
扎克·格里尔森

0

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

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

问题:Access-Control-Allow-Origin头不见了有时

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

解决方案:对于HTTP / 2调用,API网关似乎将所有标头都转换为小写,但是对于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标题时可能要检查是否区分大小写。


0

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

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


-2

就我而言,我只是写错了提取请求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。


-3

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

{ "statusCode" : 200,
'headers': 
    {'Content-Type': 'application/json',
    'Access-Control-Allow-Origin': "*"
     },
"body": json.dumps(
    {
    "temperature" : tempArray,
    "time": timeArray
    })
 }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.