AWS lambda api网关错误“格式错误的Lambda代理响应”

时间:2017-04-30 15:24:00

标签: node.js amazon-web-services aws-lambda aws-api-gateway

我正在尝试使用AWS lambda建立一个hello world示例并通过api网关提供它。我点击了“创建一个Lambda函数”,它设置了api gatway并选择了Blank Function选项。我添加了AWS gateway getting started guide上的lambda函数:

exports.handler = function(event, context, callback) {
  callback(null, {"Hello":"World"});  // SUCCESS with message
};

问题在于,当我向它发出GET请求时,它会返回502响应{ "message": "Internal server error" }。并且日志显示“由于配置错误导致执行失败:格式错误的Lambda代理响应”。

18 个答案:

答案 0 :(得分:68)

通常,当您看到Malformed Lambda proxy response时,这意味着您的Lambda函数的响应与API网关期望的格式不匹配,就像这样

{
    "isBase64Encoded": true|false,
    "statusCode": httpStatusCode,
    "headers": { "headerName": "headerValue", ... },
    "body": "..."
}

如果您未使用Lambda代理集成,则可以登录API Gateway控制台并取消选中Lambda代理集成复选框。

此外,如果您看到间歇Malformed Lambda proxy response,则可能意味着Lambda会限制对您的Lambda函数的请求,并且您需要请求Lambda函数的并发执行限制增加。

答案 1 :(得分:36)

如果lambda用作代理,则响应格式应为

{
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"body": "..."
}

注意:正文应该是字符串

答案 2 :(得分:22)

是的,所以我认为这是因为您实际上没有在那里返回正确的http响应,这就是您收到错误的原因。

我个人使用一组这样的函数:

    module.exports = {
        success: (result) => {
            return {
                statusCode: 200,
                headers: {
                    "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
                    "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
                },
                body: JSON.stringify(result),
            }
        },
        internalServerError: (msg) => {
            return {
                statusCode: 500,
                headers: {
                    "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
                    "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
                },
                body: JSON.stringify({
                    statusCode: 500,
                    error: 'Internal Server Error',
                    internalError: JSON.stringify(msg),
                }),
            }
        }
} // add more responses here.

然后你只需:

var responder = require('responder')

// some code

callback(null, responder.success({ message: 'hello world'}))

答案 3 :(得分:6)

来自AWS docs

  

在Node.js的Lambda函数中,要返回成功的响应,请调用   callback(null,{“statusCode”:200,“body”:“results”})。抛出一个   异常,调用回调(新错误('内部服务器错误'))。为一个   客户端错误,例如,缺少必需参数,您可以调用   callback(null,{“statusCode”:400,“body”:“缺少参数   ...“}}返回错误而不抛出异常。

答案 4 :(得分:3)

我遇到了这个问题,它源于无效的处理程序代码,看起来完全没问题:

exports.handler = (event, context) => {
  return {
    isBase64Encoded: false,
    body: JSON.stringify({ foo: "bar" }),
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
    statusCode: 200,
  };
}

我从检查有点混乱的 API 网关响应日志中得到了提示:

> Endpoint response body before transformations: null

修复它的方法是要么

  • 添加 async 关键字(异步函数隐式返回一个 Promise):
exports.handler = async (event, context) => {
    return {
        isBase64Encoded: false,
        body: JSON.stringify({ foo: "bar" }),
        headers: {
          'Access-Control-Allow-Origin': '*',
        },
        statusCode: 200,
    };
}
  • 返回一个承诺:
exports.handler = (event, context) => {
    return new Promise((resolve) => resolve({
        isBase64Encoded: false,
        body: JSON.stringify({ foo: "bar" }),
        headers: {
          'Access-Control-Allow-Origin': '*',
        },
        statusCode: 200,
    }));
}
  • 使用回调:
exports.handler = (event, context, callback) => {
    callback({
        isBase64Encoded: false,
        body: JSON.stringify({ foo: "bar" }),
        headers: {
          'Access-Control-Allow-Origin': '*',
        },
        statusCode: 200,
    });
}

我的处理程序之前声明为 async,但从未使用过 await,因此我删除了 async 关键字以降低代码的复杂性,而没有意识到 Lambda 期望使用 async/await/ Promise 或回调返回方法。

答案 5 :(得分:2)

一个非常特殊的情况,如果你直接传递标题,你有可能有这个标题:

web: gunicorn main_loop:app

但亚马逊需要这个:

"set-cookie": [ "........" ]

答案 6 :(得分:2)

适用于在响应看起来有效时仍在挣扎的其他任何人。这不起作用:

callback(null,JSON.stringify( {
  isBase64Encoded: false,
  statusCode: 200,
  headers: { 'headerName': 'headerValue' },
  body: 'hello world'
})

但是这样做:

callback(null,JSON.stringify( {
  'isBase64Encoded': false,
  'statusCode': 200,
  'headers': { 'headerName': 'headerValue' },
  'body': 'hello world'
})

此外,似乎在响应对象上不允许出现多余的键。

答案 7 :(得分:2)

如果将https://github.com/aws/aws-lambda-go与Go一起使用,则必须使用events.APIGatewayProxyResponse

func hello(ctx context.Context, event ImageEditorEvent) (events.APIGatewayProxyResponse, error) {
    return events.APIGatewayProxyResponse{
        IsBase64Encoded: false,
        StatusCode:      200,
        Headers:         headers,
        Body:            body,
    }, nil
}

答案 8 :(得分:1)

我已经尝试了以上所有建议,但是在body的值不是String时却无效了

return {
    statusCode: 200,
    headers: {
        "Content-Type": "application/json",
        "Access-Control-Allow-Origin": "*"
    },
    body: JSON.stringify({
        success: true
    }),
    isBase64Encoded: false
};

答案 9 :(得分:1)

我遇到此错误,因为我意外地从CloudFormation AWS :: Serverless :: Api资源中删除了变量ServerlessExpressLambdaFunctionName。这里的上下文是https://github.com/awslabs/aws-serverless-express“使用您现有的Node.js应用程序框架,在AWS Lambda和Amazon API Gateway之上运行无服务器应用程序和REST API”

答案 10 :(得分:0)

如果上述方法不适用于任何人,尽管正确设置了响应变量,我还是遇到了此错误。

我正在使用函数调用RDS数据库。原来,导致该问题的原因是该数据库上的安全组规则(入站)。

您可能想限制可以访问该API的IP地址,但是如果您想使其快速运行/变脏以测试该更改是否可以解决,则可以将其设置为接受所有此类(您可以还将端口范围设置为也接受所有端口,但在此示例中我没有这样做):

enter image description here

答案 11 :(得分:0)

“格式错误的Lambda代理响应”错误的常见原因是headers不是{String: String, ...}键/值对。

由于set-cookie标头可以并且确实以倍数出现,因此它们被表示 在http.request.callback.response中作为{<1>}的set-cookieArray 值,而不是单个Strings 。虽然这对开发人员有效,但AWS API网关不理解它,并抛出“格式错误的Lambda代理响应” 错误。

我的解决方案是执行以下操作:

String

请注意,以上function createHeaders(headers) { const singleValueHeaders = {} const multiValueHeaders = {} Object.entries(headers).forEach(([key, value]) => { const targetHeaders = Array.isArray(value) ? multiValueHeaders : singleValueHeaders Object.assign(targetHeaders, { [key]: value }) }) return { headers: singleValueHeaders, multiValueHeaders, } } var output = { ...{ "statusCode": response.statusCode, "body": responseString }, ...createHeaders(response.headers) } 并不表示 Yada Yada Yada 。是ES6 spread operator

答案 12 :(得分:0)

.net核心 C#的一段代码:

using Amazon.Lambda.APIGatewayEvents;
...
var response = new APIGatewayProxyResponse
{
   StatusCode = (int)HttpStatusCode.OK,
   Body = JsonConvert.SerializeObject(new { msg = "Welcome to Belarus! :)" }),
   Headers = new Dictionary<string, string> { { "Content-Type", "application/json" } }
};
return response;

来自lambda的响应将是:

{"statusCode":200,"headers":{"Content-Type":"application/json"},"multiValueHeaders":null,"body":"{\"msg\":\"Welcome to Belarus! :)\"}","isBase64Encoded":false}

来自api网关的响应将是:

{"msg":"Welcome to Belarus! :)"}

答案 13 :(得分:0)

这是另一种方法。在您的API网关集成请求和响应中配置映射模板。转到IntegrationRequest-> MappingTemplate->选择“当未定义模板时”->为内容类型输入application / json。然后,您不必显式发送json。甚至您在客户端得到的响应也可以是纯字符串。

答案 14 :(得分:0)

函数响应的格式是此错误的根源。为了让API Gateway处理Lambda函数的响应,该响应必须为JSON,格式为:

{ “ isBase64Encoded”:true | false, “ statusCode”:httpStatusCode, “ headers”:{“ headerName”:“ headerValue”,...}, “身体”: ”...” }

这是Node.js中的示例函数,其响应的格式正确:

exports.handler =(事件,上下文,回调)=> {

var responseBody = {
    "key3": "value3",
    "key2": "value2",
    "key1": "value1"
};

var response = {
    "statusCode": 200,
    "headers": {
        "my_header": "my_value"
    },
    "body": JSON.stringify(responseBody),
    "isBase64Encoded": false
};
callback(null, response);

};

参考:https://aws.amazon.com/premiumsupport/knowledge-center/malformed-502-api-gateway/

答案 15 :(得分:0)

Python 3.7

之前

{
    "isBase64Encoded": False,
    "statusCode": response.status_code,
    "headers": {
                  "Content-Type": "application/json",
               },
     "body": response.json()
}

之后

{
    "isBase64Encoded": False,
    "statusCode": response.status_code,
    "headers": {
                  "Content-Type": "application/json",
               },
     "body": str(response.json()) //body must be of string type
}

答案 16 :(得分:0)

如果您刚接触AWS,只是希望您的URL有效,

如果尚未为Lambda函数创建触发器,请在Lambda Functions应用中导航至该函数,然后选择API Gateway创建触发器。

导航到API网关应用程序->选择特定的Lambda的API网关(方法执行)->单击INTEGRATION Request-> 取消选中“使用Lambda代理集成” (复选框)。

然后单击“ <-方法执行”,然后单击“测试客户端”部分。提供选项,然后单击测试按钮。您应该会看到成功的响应。

如果仍然无法获得成功响应,请为正确的版本创建别名(如果Lambda函数中有多个版本)

从日志中选择URL,然后使用POST / GET Tool(邮递员)并选择身份验证作为AWS签名-在邮递员请求中提供身份验证密钥(AccessKey和SecretKey),并将AWS区域和服务名称作为lambda。

P.S:这可能仅对初学者有所帮助,并且可能与其他人无关。

答案 17 :(得分:-1)

对于Python3:

import json

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'headers': {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*'
        },
        'body': json.dumps({
            'success': True
        }),
        "isBase64Encoded": False
    }

请注意,body不需要设置,可以为空:

        'body': ''
相关问题