有没有办法更改Amazon API Gateway返回的http状态代码?

时间:2015-07-09 22:38:38

标签: amazon-web-services aws-lambda aws-api-gateway

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

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

10 个答案:

答案 0 :(得分:63)

每20-9-2016更新

亚马逊终于使用Lambda Proxy integration轻松实现了这一目标。这允许您的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 Gateway集成。

答案 1 :(得分:17)

为了能够将自定义错误对象作为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:

<强> *&#34;状态&#34;:400 *

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

<强> $ input.path(&#39; $的errorMessage&#39)

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

答案 2 :(得分:7)

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

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是正确的事情。

答案 3 :(得分:6)

对于那些尝试过这个问题并且无法完成这项工作的人(像我一样),请查看该帖子上的devvkit评论(保存我的一天):

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

完全在下面再现:

  

我自己也有这个问题,我相信换行   人物是罪魁祸首。

     

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

     

作为替代方案,您可以使用以下内容:foo(。| \ n)*

答案 4 :(得分:5)

最简单的方法是use LAMBDA_PROXY integration。使用此方法,您无需将任何特殊转换设置为API网关管道。

您的退货对象必须与下面的代码段类似:

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端点;那就是说,如果你真的不想在其他任何地方使用它,那就不是问题了。

答案 5 :(得分:4)

我想要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,点击已连接到上述lambda的已发布URL

使用高级REST客户端(或Postman)chrome插件,您将看到正确的http代码,如服务器错误(500)或400,而不是200个http响应代码,用于在&#34; httpStatusCode&#34;

来自&#39;信息中心&#39;在API网关中,我们可以看到如下的http状态代码:

400 & 500 errors

答案 6 :(得分:2)

如果使用API​​网关,这是在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调用,这似乎是客户端解析的最佳解决方案。

答案 7 :(得分: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"
        }
      }
    }
  ]
}

handler.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;

答案 8 :(得分:1)

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

#set($context.responseOverride.status =  $input.path('$.statusCode'))

答案 9 :(得分:1)

自 2021 年 2 月起生效

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

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

API 网关 enter image description here

enter image description here

Lambda

对于异步函数,只需返回带有 statusCodebody 的对象。对于同步功能使用 callback(null,obj);参考full documentation

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

结果

自定义状态码 400。

enter image description here