如何在无服务器 Lambda 中正确返回 HTTP 错误代码

12

我有一个使用Node.JS编写的无服务器Lambda函数。

返回错误代码的最佳/正确方法是什么?

我目前使用的模式 (而且它有效!) 是:

module.exports.endpoint = (event, context, callback) => {
    const response = {
        statusCode: 404,
        body: JSON.stringify({ message: 'Hello World!' })
    };
    callback(null, response);
}

当我从POSTMAN等工具拨打我的端点时,我会得到以下响应:

状态:404未找到 这正是我所期望的结果

此外,我可以在日志中看到:

Serverless: GET / (λ: get)
Serverless: [404] {"statusCode":404,"body":"{\"message\":\"Hello World!\"}"}

那很好。

让我困扰的是我正在传递 null 作为错误。查看了一些其他教程/示例,我发现了以下模式:

https://aws.amazon.com/blogs/compute/error-handling-patterns-in-amazon-api-gateway-and-aws-lambda/

https://serverless.com/framework/docs/providers/aws/events/apigateway/

callback ("the sky is falling!");

callback("[BadRequest] Validation error: Missing field 'name'");

callback("[404] Not Found");

callback(new Error('[404] Not found'));

callback(JSON.stringify(myErrorObj));

它们都很合理,可以指定HTTP状态码,但最终我得到的是HTTP状态码200。当我查看日志时,我可以看到错误紧随其后直接跟着200:

Serverless: GET / (λ: get)
Serverless: Failure: the sky is falling!
Serverless: Replying 200

Serverless: GET / (λ: get)
Serverless: Failure: [BadRequest] Validation error: Missing field 'name'
Serverless: Replying 200

Serverless: GET / (λ: get)
Serverless: Failure: [404] Not Found
Serverless: Replying 200

Serverless: GET / (λ: get)
Serverless: Failure: [404] Not found
Serverless: Replying 200

Serverless: GET / (λ: get)
Serverless: Failure: {"errorType":"InternalServerError","httpStatus":500,"message":"An unknown error has occurred. Please try again."}
Serverless: Replying 200

我在这里找到了以下解释:https://github.com/serverless/serverless/issues/4119

如果您想在该情况下响应HTTP错误,您必须将HTTP错误编码为成功的Lambda响应。

以下是示例:

Sample 403:
callback(null, { statusCode: 403, body: "Forbidden", headers: { "Content-Type": "text/plain" } });
Sample 404:
callback(null, { statusCode: 400 });

所以基本上这就是我做事的方式。为了完整起见,我可以补充一下,还有很多例子使用 context.fail(result) 或者 context.succeed(result) - 但是根据我的了解 context 已经过时了,不应该再使用(即使它仍然有效)。

使用 callback(error) 的意义是什么?

1个回答

10

如果您想在这种情况下使用HTTP错误响应,则必须将HTTP错误编码为Lambda成功响应。

这种错误处理方式仅适用于API Gateway。

就像传统的Node Web服务器(例如Express)一样,您可以使用throw new Error('Invalid Payload')抛出任何错误,中间件通常会将其转换为具有正确响应状态的HTTP响应。

在API Gateway Lambda中,可以这样编写...

function createResponse(status, body) {
  return {
    headers: {
      'Access-Control-Allow-Origin': '*'
    },
    statusCode: status,
    body: JSON.stringify(body)
  }
}

module.exports.endpoint = (event, context, callback) => {
    try {
      return callback(null, createResponse(200, processEvent(event)))
    } except (e) {
      console.error(e)

      return callback(null, createResponse(500, {
        error: 'Internal Server Error'
      }))
    }
}

基本上它是一个处理过的错误。Lambda函数成功执行但请求失败(可能是400、404或500)。

你应该始终处理错误,否则如果你的处理程序崩溃(由于运行时错误、语法错误或任何未处理的错误),你的用户将获得意外的响应(500或502),这可能不是你想要的。


请记住Lambda不仅用于API Gateway。callback(error)用于非API Gateway触发的Lambda。

例如,如果你有一个SNS触发的Lambda,你可以返回callback('Any error message here'),这将让SNS知道它失败了,因此SNS可以重试调用。


我看到你最后使用了相同的方式:return callback(null, createResponse) - 将 null 作为错误传递,然后实际的错误进入结果。 - iaforek
是的。正如我所说,您应该处理API网关Lambda的错误。 - Noel Llevares
@iaforek 你还有什么疑惑吗? - Noel Llevares
1
我并不困惑,只是对错误处理方式和相关文档感到有些失望。 - iaforek
3
那就是亚马逊网络服务(AWS)给你带来的。 :-) - Noel Llevares
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接