【问题标题】:How to return error collection/object from AWS Lambda function and map to AWS API Gateway response code如何从 AWS Lambda 函数返回错误集合/对象并映射到 AWS API Gateway 响应代码
【发布时间】:2016-01-03 19:50:17
【问题描述】:

我正在尝试从 AWS Lambda 函数返回一个对象,而不是一个简单的字符串。

// ...
    context.fail({
        "email": "Email address is too short",
        "firstname": "First name is too short"
    });
// ...

我已经使用errorMessage 将错误响应映射到状态代码,这非常棒:

// ...
    context.fail('That "username" has already been taken.');
// ...

我只是在尝试做一些 AWS API Gateway 负担不起的事情吗?

我也已经找到了这篇文章,它有帮助:Is there a way to change the http status codes returned by Amazon API Gateway?

【问题讨论】:

    标签: http amazon-web-services aws-lambda http-response-codes aws-api-gateway


    【解决方案1】:

    更新 自撰写本文以来,lambda 已更新调用签名,现在通过 event, context, callback

    您应该使用callback(err, res),而不是调用context.done(err, res)。请注意,对于 context.done 的情况仍然适用于回调模式。

    还应该补充一点,使用 API Gateways 代理和集成实现,整个线程几乎已经过时了。 如果您正在将 API Gateway 与 Lambda 集成,我建议您阅读这篇文章:http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html

    下面的原始回复

    首先,让我们澄清一些事情。

    context.done() 与 context.fail()/context.success

    context.done(error, result); 只不过是context.fail(error);context.success(response); 的包装 Lambda 文档明确指出,如果错误为非 null,则忽略结果:

    如果使用 RequestResponse(同步)调用类型调用 Lambda 函数,则该方法返回响应正文,如下所示: 如果错误为空,则将响应正文设置为结果的字符串表示形式。这类似于 context.succeed()。 如果错误不为空,则将响应正文设置为错误。 如果使用类型为 error 的单个参数调用该函数,则错误值将填充到响应正文中。 http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html

    这意味着无论您使用失败/成功或完成的组合,行为都是完全相同的。

    API 网关和响应码映射

    我已经测试了来自 Lambda 的响应处理与 API Gateway 中的响应代码映射相结合的每一种可能的组合。

    这些测试的结论是 "Lambda Error RegExp" 仅针对 Lambda 错误执行,即:您必须调用 context.done(error);context.fail(error); 才能真正触发 RegExp .

    现在,这带来了一个问题,正如已经指出的那样,Lambda 将您的错误粘贴到一个对象中,并在您提供的任何内容上调用 toString()

    { errorMessage: yourError.toString() }
    

    如果你提供了一个错误对象,你会得到这个:

    { errorMessage: "[object Object]" }
    

    一点帮助都没有。

    到目前为止我发现的唯一解决方法是调用

    context.fail(JSON.stringify(error));
    

    然后在我的客户端做:

    var errorObject = JSON.parse(error.errorMessage);
    

    它不是很优雅,但很有效。 作为我的错误的一部分,我有一个名为“代码”的属性。它可能看起来像这样:

    { 
        code: "BadRequest", 
        message: "Invalid argument: parameter name" 
    }
    

    当我对这个对象进行字符串化时,我得到:

    "{\"code\":\"BadRequest\",\"message\":\"Invalid argument: parameter name\"}"
    

    Lambda 会将此字符串粘贴到响应的 errorMessage 属性中,我现在可以在 API Gateway 响应映射中安全地 grep 查找 .*"BadRequest".*

    这是一个解决 Lambda 和 API 网关两个有点奇怪的怪癖的 hack:

    1. 为什么 Lambda 坚持包装错误而不是仅仅给出 它恢复原状?
    2. 为什么 API 网关不允许我们在 Lambda 结果,只有错误?

    我正在就这两种相当奇怪的行为向亚马逊提出支持案例。

    【讨论】:

    • 目前看来context.done 等方法要么已被弃用,要么根本不受支持。文档中没有提到它们;相反,他们假设使用callback,这是处理程序的第三个参数。它的签名与context.done 相同,即它接受error 作为第一个参数,result 作为第二个参数。
    • @MarSoft 我已更新响应以更好地反映当前的可能性和 AWS 实施
    【解决方案2】:

    您不必使用 context.fail,使用成功但发送不同的 statusCode 和 errorMessage,这是我如何格式化输出的示例:

    try {
        // Call the callable function with the defined array parameters
        // All the function called here will be catched if they throw exceptions
        result.data = callable_function.apply(this, params);
        result.statusCode = 200;
        result.operation = operation;
        result.errorMessage = ""
    } catch (e) {
        result.data = [];
        result.statusCode = 500;
        result.errorMessage = e.toString();
        result.method = method;
        result.resource = resource;
    }
    
    // If everything went smooth, send back the result
    // If context succeed is not called AWS Lambda will fire the function
    // again because it is not successfully exited
    context.succeed(result);
    

    使用消费者逻辑来处理不同的错误案例逻辑,不要忘记为函数运行的时间付费...

    【讨论】:

    • 当我尝试这个时,没有 Lambda 正则表达式错误模式,在 200 和 404 上,当我测试它时,永远不会返回 404 的响应代码。我得到了正确的数据,“statusCode”设置为 404,但实际的响应代码是 200。我错过了什么吗?
    • 是的,在集成响应中不要再次映射您的响应,只需发送 lambda 输出,并使用默认响应映射。
    • 我刚刚从“方法响应”和“集成响应”中删除了所有响应代码,当我测试时,将statusCode 设置为 200 或 400,我只得到 500。当我添加时“方法响应”中的 200 和 400 没有变化。当我在“集成响应”中添加 200 和 400 时,即使我将 statusCode 设置为 400,也只能得到 200。当我从“方法响应”中删除 200 和 400 时,我得到的只是 500。谢谢你的帮助顺便说一句.
    • Np,在“集成请求”中获取运行 lambda 所需的数据,您将在事件中拥有它,然后在“集成响应”中在 lambda 中发送您想要的状态代码你只是发送输出,你不映射它,使用“context.succeed(result)”,结果是你想要的result.statusCode。然后在您的应用程序中使用状态代码。然后,如果您希望发送回正确的 HTTP 休息代码,则可以为状态代码添加其他映射。
    • 所以,您的意思是,当您使用 context.succeed() 时,您不能将实际的 http 状态代码映射到默认值以外的任何内容。这意味着您只需要一个集成响应。对吗?
    【解决方案3】:

    您应该将context.fail 的使用替换为context.done,并仅将context.fail 用于非常严重的Lambda function 故障,因为它不允许多个输出参数。 Integration Response 能够通过对传递给 context.done 的第一个参数执行正则表达式来匹配映射模板,这也将 HTTP 状态代码映射到响应。您不能直接从Lambda 传递此响应状态代码,因为它是API Gateway Integration Response 的作用来抽象HTTP 协议。

    请参阅以下内容:

    context.done('Not Found:', <some object you can use in the model>);

    Integration Response面板这个设置:

    您可以为任何类型的错误复制类似的方法。您还应该创建错误模型并将其映射到您的响应。

    【讨论】:

    • 我已经能够让这个工作,但我无法返回一个带有身体的 400;正文包含验证错误。但我没有尝试context.fail() 的第三个参数。
    • 您需要为该响应代码添加适当的模型并使用该模型返回数据。
    • 有例子吗?昨天我花了一整天的时间试图弄清楚这一点,但找不到任何有助于解释它应该如何“工作”的东西。我在日志中看到的只是{"errorMessage": "<first argument as String>"} context.fail() 的附加参数显然是可用的。
    • 没问题。这个Lambda programming model 页面包含有关context.fail(...) 可以做什么的更多信息,它还介绍了它如何传递数据。我认为处理您要查找的内容的正确方法不是调用context.fail 而是使用context.done,因为它具有更多参数,并让API Gateway 层根据您可以正则表达式的返回字符串处理它。
    • 我会扩展我的答案。
    【解决方案4】:

    对于那些在这个问题上尝试了所有方法但无法完成这项工作的人(比如我),请查看这篇文章的 thedevkit 评论(节省了我的一天):

    https://forums.aws.amazon.com/thread.jspa?threadID=192918

    在下面完全复制它:

    我自己也遇到过这个问题,我相信换行符 角色是罪魁祸首。

    foo.* 将匹配出现的 "foo" 后跟任何字符 除了换行符。通常这是通过添加'/s'标志来解决的,即 “foo.*/s”,但 Lambda 错误正则表达式似乎不尊重这一点。

    您可以使用类似的替代方法: foo(.|\n)*

    【讨论】:

      猜你喜欢
      • 2016-07-21
      • 2017-10-04
      • 1970-01-01
      • 2018-05-02
      • 1970-01-01
      • 2017-05-08
      • 2017-04-27
      • 2019-08-03
      • 2018-02-14
      相关资源
      最近更新 更多