AWS API Gateway CORS 对 OPTIONS 正常,对 POST 失败

Posted

技术标签:

【中文标题】AWS API Gateway CORS 对 OPTIONS 正常,对 POST 失败【英文标题】:AWS API Gateway CORS ok for OPTIONS, fail for POST 【发布时间】:2017-03-02 04:18:47 【问题描述】:

我查看了关于 SO 的其他相关问题,但这似乎有所不同。 其实我的问题和this one很相似,只是我没有400状态问题。

设置:

通过 API 网关的 lambda 函数 授权:无,需要 API KEY:false

部署到阶段:测试

1 个资源,1 个集成 lambda 的 POST 方法。

直接调用 POST 端点,例如with curl 总是返回 200(有/没有有效负载、错误有效负载等) - 所以这与引用的问题不同。

我已使用“启用 CORS”选项 - 我已尝试在资源和 POST 请求(并随后部署 API)上应用此选项。

在 API GW 中,我可以看到 Access-Control-Allow-Origin 在 POST 方法 - 方法响应区域下的 200 个响应标头中列出。

结果:在 Chrome 中从客户端代码调用端点,OPTIONS 通过但 POST 由于缺少 Access-Control-Allow-Origin 标头而失败。

在 curl 中:OPTIONS 调用

curl -X OPTIONS -H "Access-Control-Request-Method: POST" \
     -H "Access-Control-Request-Headers: Content-Type" \
     -H "Origin: http://example.com" --verbose <endpoint>

回复是:

< HTTP/1.1 200 OK
< Content-Type: application/json
...
< Access-Control-Allow-Headers: Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token
< Access-Control-Allow-Methods: POST,OPTIONS
< Access-Control-Allow-Origin: *
...

但使用 POST:

curl -X POST -d '' -H "Content-Type: application/json" \
     -H "Origin: http://example.com" --verbose <endpoint>

它返回:

< HTTP/1.1 200 OK
< Content-Type: application/json
...

和响应 json 正文 - 但没有 Access-anything 标头。

我还能检查什么?

【问题讨论】:

【参考方案1】:

问题在于 API 网关使用选中的 "Lambda Proxy Integration" 选项调用了我的 lambda 函数。

我相信在将 API 网关触发器添加到新创建的 lambda 函数时,默认情况下会激活此功能。

在 API Gateway - Resource - Method 视图中,“Integration Response”框显示为灰色,并且似乎无法(即使对于 Enable CORS 功能)在那里添加 Access-Control-Allow-Origin 标头,根据 @ Abhigna_Nagaraja 是必需的。

解决方案: 如果使用“Lambda 代理集成”,请将 'Access-Control-Allow-Origin': '*' 标头添加到您的 lambda 函数中。

更好的是:在同一视图 - 集成请求中,关闭“Lambda 代理集成”并再次启用 CORS(之后部署)。

(然后,在回调中,您必须只返回有效负载 json 而不是 statusCode, headers, body 对象。)

更新

如果您不确定是在 http 状态代码还是在 json 有效负载中返回请求响应状态信息,请阅读一些有用的信息:

http status vs json status

json status standards

【讨论】:

我相信新的“Lambda 代理集成”已经损坏,因为它只创建了一个新的 ANY 方法。它似乎没有与 CORS 完美集成,甚至与默认的 Lambda 触发器向导也没有完美集成。目前,我只能通过禁用“Lambda 代理集成”并手动创建 GET/POST 方法来解决此问题。 根据我的经验,这部分是有效的。 ANY 方法是一个包罗万象的方法,在 LPI 的情况下,它将所有方法(POST、GET 等)定向到 lambda。但是,如果 lambda 有任何问题,则错误是非常具有误导性的。 “Lambda 代理集成”是一种控制 lambda 函数的状态代码和响应标头的方法。禁用代理集成将始终返回 200 响应,并且只允许您设置响应内容。当使用启用代理集成的 API GW 时,文档提到了在您的 lambda 中设置 CORS 标头。 (docs.aws.amazon.com/apigateway/latest/developerguide/…)【参考方案2】:

“启用 CORS”选项是一个方便的工具,可以设置所有集成/方法响应标头映射。如果您单击“启用 CORS”,然后添加了新资源,它将没有所需的设置。您可以再次单击“启用 CORS”,也可以手动将其设置为

将“Access-Control-Allow-Origin”方法响应标头添加到 POST 方法 将“Access-Control-Allow-Origin”集成响应头映射添加到 POST 方法

另外,不要忘记在使用 curl 测试更改之前部署 API。

【讨论】:

一切都按照您的建议完成。但是,在使用手动步骤确认时,我注意到一件事:方法响应看起来不错,但无法查看或编辑集成响应。该框显示“代理集成无法配置为转换响应”。我正在使用 Lambda 代理集成。这可能与我看到的问题有关吗? 我能够通过将标头添加到 lambda 回调中的标头部分来获取标头。由于这看起来像是代码和配置的丑陋组合,我怀疑我们不应该在需要 CORS 时使用 Lambda 代理集成? 您知道在 LPI 中将 CORS 标头添加到集成响应中是否已修复?【参考方案3】:

如果您愿意使用 serverless-express 在您的 Lambda 中封装一个简单的 Express 应用程序,那么 Express cors package 可以让这个非常简单且高度可配置为 Lambda 代理。无需在 API Gateway 级别配置 CORS。

index.js

const app = express();
app.use(cors());
// ...your backend implementation

lambda.js

const serverlessExpress = require('@vendia/serverless-express')
const app = require('./app')
exports.handler = serverlessExpress( app )

【讨论】:

以上是关于AWS API Gateway CORS 对 OPTIONS 正常,对 POST 失败的主要内容,如果未能解决你的问题,请参考以下文章

AWS API Gateway + AWS Lambda 中的 CORS

AWS CDK API Gateway 启用 Cors

AWS API Gateway CORS 问题

使用 BOTO3 为 AWS Api Gateway 自动化 CORS

AWS API Gateway 429 响应 - 没有 CORS 标头

AWS API Gateway 中的 CORS 配置