Amazon web services 有没有办法更改AmazonAPI网关返回的http状态码?
例如,如果我想为无效参数返回一个特定的400错误,或者当lambda函数调用导致创建错误时返回一个201错误Amazon web services 有没有办法更改AmazonAPI网关返回的http状态码?,amazon-web-services,aws-lambda,aws-api-gateway,Amazon Web Services,Aws Lambda,Aws Api Gateway,例如,如果我想为无效参数返回一个特定的400错误,或者当lambda函数调用导致创建错误时返回一个201错误 我希望有不同的http状态代码,但api网关似乎总是返回200状态代码,即使lambda函数返回错误。以下是返回自定义http状态代码和自定义错误消息的最快方法: 在API网关仪表板中,执行以下操作: 在资源的方法中,单击方法响应 在HTTP状态表中,单击AddResponse,然后添加要使用的每个HTTP状态代码 在资源的方法中,单击集成响应 为前面创建的每个HTTP状态代码添加集成响
我希望有不同的http状态代码,但api网关似乎总是返回200状态代码,即使lambda函数返回错误。以下是返回自定义http状态代码和自定义
错误消息的最快方法:
在API网关仪表板中,执行以下操作:
在资源的方法中,单击方法响应
在HTTP状态表中,单击AddResponse,然后添加要使用的每个HTTP状态代码
在资源的方法中,单击集成响应
为前面创建的每个HTTP状态代码添加集成响应。确保已选中输入传递。使用lambda error regex确定从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: .*
您的API网关路由应返回以下内容:
HTTP Status Code: 400
JSON Error Response:
{
errorMessage: "Bad Request: You submitted invalid input"
}
我认为没有办法复制这些设置并将其用于不同的方法,所以我们有很多烦人的冗余手动输入要做
我的集成响应如下所示:
对于那些尝试了所有方法解决这个问题但无法解决这个问题的人(像我一样),请查看这篇帖子上的thedevkit评论(拯救了我的一天):
完全复制如下:
我自己也有过一些问题,我相信新线
人物是罪魁祸首
foo.*将匹配后跟任何字符的“foo”
除了新线。通常通过添加“/s”标志来解决此问题,即。
“foo.*/s”,但Lambda错误regex似乎不尊重这一点
作为替代方案,您可以使用以下内容:foo(.|\n)*
为了能够将自定义错误对象作为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网关的响应流程:
根据2016年9月20日更新
Amazon最终通过使用。这允许Lambda函数返回正确的HTTP代码和标头:
let response = {
statusCode: '400',
body: JSON.stringify({ error: 'you messed up!' }),
headers: {
'Content-Type': 'application/json',
}
};
context.succeed(response);
告别API网关中的请求/响应映射
选项2
使用将现有Express应用程序与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调用,这似乎是客户端解析的最佳解决方案。我希望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 of/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')
现在,publish/res1/service1,点击已发布的URL,该URL连接到上面的lambda
使用高级REST客户端(或邮递员)chrome插件,您将看到正确的http代码,如服务器错误(500)或400,而不是“httpStatusCode”中给出的所有请求的200 http响应代码
从API的“仪表板”中,在API网关中,我们可以看到如下http状态代码:
1)通过选中API网关资源定义的“集成请求”屏幕上标记为“使用Lambda代理集成”的复选框,配置要使用的API网关资源。(或者在cloudformation/terraform/serverless/etc配置中定义)
2)用两种方法更改lambda代码
- 适当地处理传入的
事件
(第一个函数参数)。它不再只是简单的负载,它代表整个HTTP请求,包括头、查询字符串和正文。下面是示例。关键点是JSON主体将是需要显式JSON.parse(event.body)
call的字符串(不要忘记try/catch
)。下面是一个例子
- 通过使用null调用回调进行响应,然后调用一个响应对象,该对象提供HTTP详细信息,包括
statusCode
、body
、和头
。
body
应该是一个字符串,也可以根据需要使用JSON.stringify(有效负载)
statusCode
可以是数字
标题
是标题名称到值的对象
代理集成的Lambda事件参数示例
示例回调响应形状
注释
-我相信context
上的方法,例如context.succeed()
已经被弃用了。它们不再被记录,尽管它们似乎仍然有效。我认为编写回调API是正确的做法。最简单的方法是。使用这种方法,您不需要在API网关管道中设置任何特殊的转换
您的返回对象必须类似于下面的代码段:
module.exports.lambdaHandler=(事件、上下文、完成)=>{
// ...
让r
{
"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'
}
})
#set($context.responseOverride.status = $input.path('$.statusCode'))
export const dummyFunction = async (event, context, callback) =>
{
// ... logic
return {
statusCode: 400,
body: JSON.stringify({...data}),
}
};