例如,如果我想为无效参数返回特定的 400 错误,或者当 lambda 函数调用导致创建时返回 201。
我想要不同的 http 状态代码,但看起来 api 网关总是返回 200 状态代码,即使 lambda 函数返回错误也是如此。
例如,如果我想为无效参数返回特定的 400 错误,或者当 lambda 函数调用导致创建时返回 201。
我想要不同的 http 状态代码,但看起来 api 网关总是返回 200 状态代码,即使 lambda 函数返回错误也是如此。
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 网关集成。
这是返回自定义 HTTP 状态代码和自定义的最快方法errorMessage
:
在 API Gateway 仪表板中,执行以下操作:
为您之前创建的每个 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: .*
您的 API Gateway 路由应返回以下内容:
HTTP Status Code: 400
JSON Error Response:
{
errorMessage: "Bad Request: You submitted invalid input"
}
我认为没有办法复制这些设置并将其重新用于不同的方法,所以我们有很多烦人的冗余手动输入要做!
我的集成响应如下所示:
为了能够以 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/
1)通过选中API Gateway 资源定义的“集成请求”屏幕上标记为“使用 Lambda 代理集成”的复选框,将您的 API Gateway 资源配置为使用Lambda 代理集成。(或在您的 cloudformation/terraform/serverless/etc 配置中定义它)
2)以 2 种方式更改您的 lambda 代码
event
(第一个函数参数)。它不再只是裸露的负载,它代表了整个 HTTP 请求,包括标头、查询字符串和正文。示例如下。关键是 JSON 主体将是需要显式JSON.parse(event.body)
调用的字符串(不要忘记try/catch
这一点)。示例如下。statusCode
、body
和headers
。
body
应该是一个字符串,所以JSON.stringify(payload)
根据需要做statusCode
可以是一个数字headers
是标头名称到值的对象{
"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 进行编码是正确的事情。
我希望 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 状态码:
最简单的方法是使用 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 端点;也就是说,如果您真的不打算在其他任何地方使用它,那也不是什么大问题。
对于那些在这个问题上尝试了一切但无法完成这项工作的人(比如我),请查看这篇文章的 thedevkit 评论(节省了我的一天):
https://forums.aws.amazon.com/thread.jspa?threadID=192918
在下面完全复制它:
我自己也遇到过这个问题,我相信换行符是罪魁祸首。
foo.* 将匹配出现的“foo”,后跟除换行符以外的任何字符。通常这是通过添加'/s'标志来解决的,即“foo.*/s”,但 Lambda 错误正则表达式似乎不尊重这一点。
作为替代方案,您可以使用类似: foo(.|\n)*
如果使用 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 调用,这似乎是客户端解析的最佳解决方案。
如果您不想使用代理,可以使用此模板:
#set($context.responseOverride.status = $input.path('$.statusCode'))
我正在使用无服务器 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;
自 2021 年 2 月起有效
设置自定义 HTTP 状态代码的最简单方法是在 API Gateway 中设置 Lambda 代理集成。
在 API Gateway > Resource > Actions Dropdown > Create Method > 勾选Lambda Proxy Integration
并选择适当的 Lambda 函数。
拉姆达
对于异步函数,只需返回一个带有statusCode
and的对象body
。用于同步功能callback(null,obj)
;参考完整的文档。
export const dummyFunction = async (event, context, callback) =>
{
// ... logic
return {
statusCode: 400,
body: JSON.stringify({...data}),
}
};
结果
自定义状态码 400。