Lambda 函数向 CloudFront 返回了无效的请求或响应

The Lambda function returned an invalid request or response to CloudFront

我正在尝试按照此处的说明进行操作 https://medium.com/@tom.cook/edge-lambda-cloudfront-custom-headers-3d134a2c18a2

我已让 CloudFront 成功地位于静态 S3 "hello world" HTML 文件前,我想使用 lambda edge 设置额外的 headers,但出现错误。真正令人沮丧的是我找不到任何错误日志来调试出了什么问题。这是浏览器显示的内容。

ERROR

The request could not be satisfied.

The Lambda function returned an invalid request or response to CloudFront. 
Generated by cloudfront (CloudFront)
Request ID: 2Cqex7euzH0Iigps58i9tMVxdqAaLznL2ZjwqR1sW1AZHz6x2EwfMA==

这是我的简单 lambda 的代码:

exports.handler = (event, context, callback) => {
    console.log(event)
    callback(null, 'Hello from Lambda');
};

触发器类型是 viewer-response 并附加到我的 CloudFront 分配(如果重要的话,使用 Cache Behavior: *)。 lambda 具有对应于 AWSLambdaBasicExecutionRole 的角色,它授予对 Cloudwatch 的写入权限。

一旦启用触发器,对 Web 请求的响应就会从我的 "Hello world" HTML 变为上述错误,因此我知道它正在触发 lambda。但在 lambda 仪表板中,它没有显示任何调用或错误。 Cloudwatch 中没有日志出现。 CloudFront 仪表板显示错误 (5xx),但没有来自 lambda 的错误。

如果我随后通过单击已部署函数、将测试事件配置为 "CloudFront Modify Response Header," 并点击测试来在 lambda 控制台中测试我的函数,它会成功。 Cloudwatch 显示测试的日志和控制台输出!但是实时调用的日志中仍然没有任何内容。

我唯一的理论是权限有问题,CloudFront 实际上无法调用 lambda(解释了为什么 lambda 仪表板中没有任何内容)。最后一件事是 CloudFront 日志(在 S3 中)显示带有 502 错误和 LambdaValidationError 的 Web 请求,但我不知道这是否有帮助。

您正在查看的博客 post 中的示例在 Lambda@Edge 仍处于预览阶段时有效(特定客户的访问受限,在正式发布之前),但它不再有效正确的。在服务启动前不久,数据结构发生了变化。

响应 header 数据结构以前如下所示:

headers['Strict-Transport-Security'] = "max-age=31536000; includeSubdomains; preload";
headers['Content-Security-Policy']   = "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'";
headers['X-Content-Type-Options']    = "nosniff";

新结构如下所示:

headers['strict-transport-security'] = [{
    key:   'Strict-Transport-Security', 
    value: "max-age=31536000; includeSubdomains; preload"
}];

headers['content-security-policy'] = [{
    key:   'Content-Security-Policy', 
    value: "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'"
}];

headers['x-content-type-options'] = [{
    key:   'X-Content-Type-Options',
    value: "nosniff"
}];

外部 object 中的键必须是内部 object 的每个成员中 key 值的小写等效项。为了更准确地反映必须处理 HTTP header 的方式,很可能需要对数据结构进行这种更改,因为在 HTTP/1.x 中它们不区分大小写,但在 Javascriptobject,按键区分大小写

如果您的代码return编辑的结构不符合 CloudFront 对 Lambda@Edge 的要求 return,您看到的错误确实会被抛出。没有生成日志,因为日志没有地方可以去——这个错误发生在 Lambda 之外,在 Lambda 和 CloudFront 之间的接口边界的 CloudFront 一侧,它不生成任何 user-accessible 日志.

请参阅 Response Event Structure 的文档。

Lambda@Edge 和 CloudFront 有一些共同点 "gotchas"。您需要:

  • 发布 Lambda 函数的新版本
  • 将 CloudFront Lambda 关联更新为您的新版本,例如arn:aws:lambda:us-east-1:572007530218:function:gofaas-WebAuthFunction:45
  • 请求者
  • 的区域中查找 Lambda@Edge 日志

据我所知,您看不到有关从您的主要 Lambda 函数的 "copies" 分布到 "edges" 的调用的指标。

这与 "normal" Lambda Web 控制台流程不同,后者保存代码更改并从监控选项卡跳转到日志。

看看 this boilerplate app that automates deploying a Lambda@Edge OAuth and Cookie handler,它消除了很多设置的痛苦。