108

例如,如果我想为无效参数返回特定的 400 错误,或者当 lambda 函数调用导致创建时返回 201。

我想要不同的 http 状态代码,但看起来 api 网关总是返回 200 状态代码,即使 lambda 函数返回错误也是如此。

4

12 回答 12

96

2016 年 9 月 20 日更新

亚马逊最终使用Lambda 代理集成让这一切变得简单。这允许您的 Lambda 函数返回正确的 HTTP 代码和标头:

let response = {
    statusCode: '400',
    body: JSON.stringify({ error: 'you messed up!' }),
    headers: {
        'Content-Type': 'application/json',
    }
};

context.succeed(response);

告别 API 网关中的请求/响应映射!

选项 2

使用aws-serverless-express将现有 Express 应用程序与 Lambda/API 网关集成。

于 2016-10-08T19:00:04.423 回答
77

这是返回自定义 HTTP 状态代码和自定义的最快方法errorMessage

在 API Gateway 仪表板中,执行以下操作:

  1. 资源的方法中,单击方法响应
  2. HTTP 状态表中,单击添加响应并添加您想要使用的每个 HTTP 状态代码。
  3. 在您的资源的方法中,单击集成响应
  4. 为您之前创建的每个 HTTP 状态代码添加一个集成响应。确保检查输入直通。使用lambda 错误正则表达式来确定当您从 lambda 函数返回错误消息时应使用哪个状态代码。例如:

    // Return An Error Message String In Your Lambda Function
    
    return context.fail('Bad Request: You submitted invalid input');
    
    // Here is what a Lambda Error Regex should look like.
    // Be sure to include the period and the asterisk so any text
    // after your regex is mapped to that specific HTTP Status Code
    
    Bad Request: .*
    
  5. 您的 API Gateway 路由应返回以下内容:

    HTTP Status Code: 400
    JSON Error Response: 
        {
            errorMessage: "Bad Request: You submitted invalid input"
        }
    
  6. 我认为没有办法复制这些设置并将其重新用于不同的方法,所以我们有很多烦人的冗余手动输入要做!

我的集成响应如下所示:

aws api 网关 lambda 错误响应处理

于 2015-07-12T19:47:58.017 回答
19

为了能够以 JSON 格式返回自定义错误对象,您必须跳过几个环节。

首先,您必须使 Lambda 失败并传递给它一个字符串化的 JSON 对象:

exports.handler = function(event, context) {
    var response = {
        status: 400,
        errors: [
            {
              code:   "123",
              source: "/data/attributes/first-name",
              message:  "Value is too short",
              detail: "First name must contain at least three characters."
            },
            {
              code:   "225",
              source: "/data/attributes/password",
              message: "Passwords must contain a letter, number, and punctuation character.",
              detail: "The password provided is missing a punctuation character."
            },
            {
              code:   "226",
              source: "/data/attributes/password",
              message: "Password and password confirmation do not match."
            }
        ]
    }

    context.fail(JSON.stringify(response));
};

接下来,您为要返回的每个状态代码设置正则表达式映射。使用我在上面定义的对象,您可以将此正则表达式设置为 400:

.*“状态”:400.*

最后,您设置一个映射模板以从 Lambda 返回的 errorMessage 属性中提取 JSON 响应。映射模板如下所示:

$input.path('$.errorMessage')

我写了一篇关于此的文章,更详细地解释了从 Lambda 到 API Gateway 的响应流程:http: //kennbrodhagen.net/2016/03/09/how-to-return-a-custom-error-object -and-status-code-from-api-gateway-with-lambda/

于 2016-03-13T15:17:53.523 回答
11

1)通过选中API Gateway 资源定义的“集成请求”屏幕上标记为“使用 Lambda 代理集成”的复选框,将您的 API Gateway 资源配置为使用Lambda 代理集成。(或在您的 cloudformation/terraform/serverless/etc 配置中定义它)

2)以 2 种方式更改您的 lambda 代码

  • 适当地处理传入的event(第一个函数参数)。它不再只是裸露的负载,它代表了整个 HTTP 请求,包括标头、查询字符串和正文。示例如下。关键是 JSON 主体将是需要显式JSON.parse(event.body)调用的字符串(不要忘记try/catch这一点)。示例如下。
  • 通过使用 null 调用回调,然后是提供 HTTP 详细信息的响应对象来响应,包括statusCodebodyheaders
    • body应该是一个字符串,所以JSON.stringify(payload)根据需要做
    • statusCode可以是一个数字
    • headers是标头名称到值的对象

代理集成的示例 Lambda 事件参数

{
    "resource": "/example-path",
    "path": "/example-path",
    "httpMethod": "POST",
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "CloudFront-Forwarded-Proto": "https",
        "CloudFront-Is-Desktop-Viewer": "true",
        "CloudFront-Is-Mobile-Viewer": "false",
        "CloudFront-Is-SmartTV-Viewer": "false",
        "CloudFront-Is-Tablet-Viewer": "false",
        "CloudFront-Viewer-Country": "US",
        "Content-Type": "application/json",
        "Host": "exampleapiid.execute-api.us-west-2.amazonaws.com",
        "User-Agent": "insomnia/4.0.12",
        "Via": "1.1 9438b4fa578cbce283b48cf092373802.cloudfront.net (CloudFront)",
        "X-Amz-Cf-Id": "oCflC0BzaPQpTF9qVddpN_-v0X57Dnu6oXTbzObgV-uU-PKP5egkFQ==",
        "X-Forwarded-For": "73.217.16.234, 216.137.42.129",
        "X-Forwarded-Port": "443",
        "X-Forwarded-Proto": "https"
    },
    "queryStringParameters": {
        "bar": "BarValue",
        "foo": "FooValue"
    },
    "pathParameters": null,
    "stageVariables": null,
    "requestContext": {
        "accountId": "666",
        "resourceId": "xyz",
        "stage": "dev",
        "requestId": "5944789f-ce00-11e6-b2a2-dfdbdba4a4ee",
        "identity": {
            "cognitoIdentityPoolId": null,
            "accountId": null,
            "cognitoIdentityId": null,
            "caller": null,
            "apiKey": null,
            "sourceIp": "73.217.16.234",
            "accessKey": null,
            "cognitoAuthenticationType": null,
            "cognitoAuthenticationProvider": null,
            "userArn": null,
            "userAgent": "insomnia/4.0.12",
            "user": null
        },
        "resourcePath": "/example-path",
        "httpMethod": "POST",
        "apiId": "exampleapiid"
    },
    "body": "{\n  \"foo\": \"FOO\",\n  \"bar\": \"BAR\",\n  \"baz\": \"BAZ\"\n}\n",
    "isBase64Encoded": false
}

示例回调响应形状

callback(null, {
  statusCode: 409,
  body: JSON.stringify(bodyObject),
  headers: {
    'Content-Type': 'application/json'
  }
})

注释 - 我相信context诸如此类的方法context.succeed()已被弃用。尽管它们似乎仍然有效,但它们不再被记录在案。我认为对回调 API 进行编码是正确的事情。

于 2016-12-29T20:04:16.787 回答
8

我希望 Lambda 的错误是正确的 500 错误,经过大量研究后,我想出了以下内容,该错误有效:

在 LAMBDA 上

为了获得良好的回应,我返回如下:

exports.handler = (event, context, callback) => {
    // ..

    var someData1 =  {
        data: {
            httpStatusCode: 200,
            details: [
                {
                    prodId: "123",
                    prodName: "Product 1"
                },
                {
                    "more": "213",
                    "moreDetails": "Product 2"
                }
            ]
        }
    };
    return callback(null, someData1);
}

对于不好的响应,返回如下

exports.handler = (event, context, callback) => {
    // ..

    var someError1 = {
        error: {
            httpStatusCode: 500,
            details: [
                {
                    code: "ProductNotFound",
                    message: "Product not found in Cart",
                    description: "Product should be present after checkout, but not found in Cart",
                    source: "/data/attributes/product"
                },
                {
                    code: "PasswordConfirmPasswordDoesntMatch",
                    message: "Password and password confirmation do not match.",
                    description: "Password and password confirmation must match for registration to succeed.",
                    source: "/data/attributes/password",
                }
            ]
        }
    };

    return callback(new Error(JSON.stringify(someError1)));
}

在 API 网关上

对于 GET METHOD,说 /res1/service1 的 GET:

Through Method Response > Add Response, added 3 responses:
- 200
- 300
- 400

然后,

Through 'Integration Response' > 'Add integration response', create a Regex for 400 errors (client error):

Lambda Error Regex    .*"httpStatusCode":.*4.*

'Body Mapping Templates' > Add mapping template as:  
    Content-Type                 application/json  
    Template text box*           $input.path('$.errorMessage')  


Similarly, create a Regex for 500 errors (server error):

Lambda Error Regex    .*"httpStatusCode":.*5.*

'Body Mapping Templates' > Add mapping template as:  
    Content-Type                 application/json  
    Template text box*           $input.path('$.errorMessage')  

现在,发布 /res1/service1,点击发布的 URL,它连接到上面的 lambda

使用高级 REST 客户端(或 Postman)chrome 插件,您将看到正确的 http 代码,如服务器错误 (500) 或 400,而不是“httpStatusCode”中给出的所有请求的 200 个 http 响应代码。

在 API 的“仪表板”中,在 API Gateway 中,我们可以看到如下 http 状态码:

400 和 500 错误

于 2016-12-27T11:05:57.590 回答
8

最简单的方法是使用 LAMBDA_PROXY 集成。使用此方法,您无需在 API Gateway 管道中设置任何特殊转换。

您的返回对象必须类似于下面的代码段:

module.exports.lambdaHandler = (event, context, done) => {
    // ...
    let response = {
        statusCode: 200, // or any other HTTP code
        headers: {       // optional
             "any-http-header" : "my custom header value"
        },
        body: JSON.stringify(payload) // data returned by the API Gateway endpoint
    };
    done(null, response); // always return as a success
};

它确实有一些缺点:必须特别注意错误处理,以及将 lambda 函数耦合到 API Gateway 端点;也就是说,如果您真的不打算在其他任何地方使用它,那也不是什么大问题。

于 2017-01-31T03:00:34.577 回答
7

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

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

在下面完全复制它:

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

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

作为替代方案,您可以使用类似: foo(.|\n)*

于 2016-02-17T17:27:59.123 回答
2

如果使用 API Gateway,这就是 AWS Compute Blog 上推荐的方式。检查集成是否适用于直接 Lambda 调用。

var myErrorObj = {
    errorType : "InternalServerError",
    httpStatus : 500,
    requestId : context.awsRequestId,
    message : "An unknown error has occurred. Please try again."
}
callback(JSON.stringify(myErrorObj));

对于直接 Lambda 调用,这似乎是客户端解析的最佳解决方案。

于 2016-11-15T17:16:17.950 回答
2

如果您不想使用代理,可以使用此模板:

#set($context.responseOverride.status =  $input.path('$.statusCode'))
于 2020-05-26T12:02:26.257 回答
1

我正在使用无服务器 0.5。就我而言,这就是它的工作原理

s-function.json:

{
  "name": "temp-err-test",
  "description": "Deployed",
  "runtime": "nodejs4.3",
  "handler": "path/to/handler.handler",
  "timeout": 6,
  "memorySize": 1024,
  "endpoints": [
    {
      "path": "test-error-handling",
      "method": "GET",
      "type": "AWS_PROXY",
      "responses": {
        "default": {
          "statusCode": "200"
        }
      }
    }
  ]
}

处理程序.js:

'use strict';
function serveRequest(event, context, cb) {
  let response = {
    statusCode: '400',
    body: JSON.stringify({ event, context }),
    headers: {
      'Content-Type': 'application/json',
    }
  };
  cb(null, response);
}
module.exports.handler = serveRequest;
于 2016-10-21T12:07:42.283 回答
1

自 2021 年 2 月起有效

设置自定义 HTTP 状态代码的最简单方法是在 API Gateway 中设置 Lambda 代理集成。

在 API Gateway > Resource > Actions Dropdown > Create Method > 勾选Lambda Proxy Integration并选择适当的 Lambda 函数。

API 网关 在此处输入图像描述

在此处输入图像描述

拉姆达

对于异步函数,只需返回一个带有statusCodeand的对象body。用于同步功能callback(null,obj);参考完整的文档

export const dummyFunction = async (event, context, callback) => 
{
 // ... logic
   return {
   statusCode: 400,
   body: JSON.stringify({...data}),
   }
};

结果

自定义状态码 400。

在此处输入图像描述

于 2021-02-24T05:43:30.107 回答
0

我有一个快速应用程序,并在它前面使用了带有 http 集成的 api 网关。要从我的应用程序返回状态代码而不是 200 OK ,我只需将应用程序的错误处理程序返回的 http 状态代码添加到集成响应部分的 http 状态正则表达式中,它就可以正常工作。确保您的应用程序正确处理错误。 在此处输入图像描述

于 2021-12-05T18:38:05.250 回答