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

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

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

每20-9-2016更新一次

亚马逊最终使用Lambda Proxy集成简化了这个过程。 这允许您的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集成。

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

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

  1. 资源方法中,单击方法响应
  2. 在“ HTTP状态”表中,单击添加响应 ,然后添加您想要使用的每个“HTTP状态码”。
  3. 在您的资源方法中,单击集成响应
  4. 为您之前创build的每个HTTP状态代码添加一个集成响应 。 确保input传递被检查。 使用lambda错误正则expression式来确定从您的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网关路线应该返回这个:

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

我的积分响应如下所示:

aws api网关lambda错误响应处理

为了能够以JSON的forms返回一个自定义的错误对象,你必须通过几个循环来跳转。

首先,你必须让Lambda失败并传递一个string化的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)); }; 

接下来,您为每个想要返回的状态码设置正则expression式映射。 使用我上面定义的对象,你将设置这个正则expression式为400:

。* “状态”:400 *

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

$ input.path( '$。的errorMessage')

我写了一篇关于这方面的文章,详细解释了从Lambda到API网关的响应stream程: http : //kennbrodhagen.net/2016/03/09/how-to-return-a-custom-error-object -and状态码,从-API网关与-拉姆达/

1)通过在API网关资源定义的“集成请求”屏幕上选中标记为“使用Lambda代理集成”的checkbox,将API网关资源configuration为使用Lambda代理集成 。 (或者在你的cloudformation / terraform / serverless / etcconfiguration中定义它)

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

  • 适当处理传入event (第一个函数参数)。 它不再是单纯的有效载荷,它代表了整个HTTP请求,包括标题,查询string和主体。 下面的示例。 关键是JSON体将是需要显式JSON.parse(event.body)调用的string(不要忘记try/catch )。 示例如下。
  • 通过使用null调用callback来响应,然后提供一个响应对象,提供HTTP详细信息,包括statusCodebodyheaders
    • body应该是一个string,所以根据需要做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响应形状

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

笔记 – 我相信context的方法,如context.succeed()已被弃用。 尽pipe他们似乎仍然有效,但他们不再被logging在案。 我认为编码到callbackAPI是未来的正确的事情。

对于那些试图解决这个问题的所有人,无法做到这一点(像我一样),请检查这个post的评论(保存我的日子):

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

在下面完全重现:

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

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

作为替代,你可以使用像:foo(。| \ n)*

我想从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方法,请说GET / res1 / service1:

 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客户端(或邮政)铬插件,你会看到正确的http代码,如服务器错误(500)或400,而不是200 HTTP响应代码的所有请求在“httpStatusCode”中给出。

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

400和500错误

最简单的方法是使用LAMBDA_PROXY集成 。 使用此方法,您不需要将任何特殊的转换设置到API网关pipe道中。

您的返回对象将不得不类似于下面的代码片段:

 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 }; 

它有一些缺点:必须特别小心error handling,并将您的lambda函数耦合到API网关端点; 如果你不打算在其他地方使用它,那就不是什么大问题。

我正在使用无服务器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; 

如果使用API​​网关,则这是在AWS Compute博客上推荐的方式。 检查集成是否适用于直接的Lambda调用。

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

对于直接的Lambda调用,这似乎是在客户端parsing的最佳解决scheme。