简体   繁体   English

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

[英]AWS lambda api gateway error "Malformed Lambda proxy response"

I am trying to set up a hello world example with AWS lambda and serving it through api gateway.我正在尝试使用 AWS lambda 设置一个 hello world 示例并通过 api 网关为其提供服务。 I clicked the "Create a Lambda Function", which set up the api gatway and selected the Blank Function option.我单击“创建 Lambda 函数”,它设置了 api 网关并选择了空白函数选项。 I added the lambda function found on AWS gateway getting started guide :我添加了AWS 网关入门指南中的 lambda 函数:

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

The issue is that when I make a GET request to it, it's returning back a 502 response { "message": "Internal server error" } .问题是当我向它发出 GET 请求时,它会返回 502 响应{ "message": "Internal server error" } And the logs say "Execution failed due to configuration error: Malformed Lambda proxy response".并且日志显示“由于配置错误,执行失败:格式错误的 Lambda 代理响应”。

Usually, when you see Malformed Lambda proxy response , it means your response from your Lambda function doesn't match the format API Gateway is expecting, like this通常,当您看到Malformed Lambda proxy response ,这意味着您来自 Lambda 函数的响应与 API Gateway 期望的格式不匹配,如下所示

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

If you are not using Lambda proxy integration, you can login to API Gateway console and uncheck the Lambda proxy integration checkbox.如果您没有使用 Lambda 代理集成,您可以登录 API Gateway 控制台并取消选中 Lambda 代理集成复选框。

Also, if you are seeing intermittent Malformed Lambda proxy response , it might mean the request to your Lambda function has been throttled by Lambda, and you need to request a concurrent execution limit increase on the Lambda function.此外,如果您看到间歇性Malformed Lambda proxy response ,则可能意味着对您的 Lambda 函数的请求已被 Lambda 限制,您需要请求增加 Lambda 函数的并发执行限制。

If lambda is used as a proxy then the response format should be如果 lambda 用作代理,则响应格式应为

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

Note : The body should be stringified注意:正文应该是字符串化的

Yeah so I think this is because you're not actually returning a proper http response there which is why you're getting the error.是的,所以我认为这是因为您实际上并没有在那里返回正确的 http 响应,这就是您收到错误的原因。

personally I use a set of functions like so:我个人使用一组像这样的函数:

    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.

Then you simply do:然后您只需执行以下操作:

var responder = require('responder')

// some code

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

For Python3:对于 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
    }

Note the body isn't required to be set, it can just be empty:请注意,不需要设置body ,它可以为空:

        'body': ''

From the AWS docs来自AWS 文档

In a Lambda function in Node.js, To return a successful response, call callback(null, {"statusCode": 200, "body": "results"}).在 Node.js 的 Lambda 函数中,要返回成功的响应,请调用 callback(null, {"statusCode": 200, "body": "results"})。 To throw an exception, call callback(new Error('internal server error')).要抛出异常,请调用 callback(new Error('internal server error'))。 For a client-side error, eg, a required parameter is missing, you can call callback(null, {"statusCode": 400, "body": "Missing parameters of ..."}) to return the error without throwing an exception.对于客户端错误,例如缺少必需的参数,您可以调用 callback(null, {"statusCode": 400, "body": "Missing parameters of ..."}) 返回错误而不抛出例外。

I've tried all of above suggestion but it doesn't work while body value is not String我已经尝试了以上所有建议,但是当body值不是String时它不起作用

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

Just a piece of code for .net core and C# :只是一段.net coreC#的代码:

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;

Response from lambda will be :来自 lambda 的响应将是:

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

Response from api gateway will be :来自 api 网关的响应将是:

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

I had this issue, which originated from an invalid handler code which looks completely fine:我遇到了这个问题,它源于一个看起来完全没问题的无效处理程序代码:

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

I got the hint from examining the somewhat confusing API Gateway response logs:我从检查有点混乱的 API 网关响应日志中得到了提示:

> Endpoint response body before transformations: null

The way to fix it would be to either修复它的方法是要么

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

My handler was previously declared async without ever using await , so I removed the async keyword to reduce complexity of the code, without realizing that Lambda expects either using async/await/Promise or callback return method.我的处理程序之前被声明为async没有使用await ,所以我删除了async关键字以降低代码的复杂性,没有意识到 Lambda 期望使用 async/await/Promise 或回调返回方法。

A very very special case, if you pass the headers directly there is a chance you have this header:一个非常特殊的情况,如果您直接传递标头,则有可能拥有此标头:

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

But Amazon needs this:但亚马逊需要这个:

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

For anyone else who struggles when the response appears valid.对于在响应似乎有效时挣扎的其他任何人。 This does not work:这不起作用:

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

but this does:但这确实:

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

Also, it appears that no extra keys are allowed to be present on the response object.此外,似乎不允许在响应对象上存在额外的键。

If you're using Go with https://github.com/aws/aws-lambda-go , you have to use events.APIGatewayProxyResponse .如果您将 Go 与https://github.com/aws/aws-lambda-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
}

I had this error because I accidentally removed the variable ServerlessExpressLambdaFunctionName from the CloudFormation AWS::Serverless::Api resource.我遇到此错误是因为我不小心从 CloudFormation AWS::Serverless::Api 资源中删除了变量 ServerlessExpressLambdaFunctionName。 The context here is https://github.com/awslabs/aws-serverless-express "Run serverless applications and REST APIs using your existing Node.js application framework, on top of AWS Lambda and Amazon API Gateway"这里的上下文是https://github.com/awslabs/aws-serverless-express “使用现有的 Node.js 应用程序框架在 AWS Lambda 和 Amazon API 网关之上运行无服务器应用程序和 REST API”

In case the above doesn't work for anyone, I ran into this error despite setting the response variable correctly.如果上述内容对任何人都不起作用,尽管正确设置了响应变量,但我还是遇到了这个错误。

I was making a call to an RDS database in my function.我正在我的函数中调用 RDS 数据库。 It turned out that what was causing the problem was the security group rules (inbound) on that database.事实证明,导致问题的原因是该数据库上的安全组规则(入站)。

You'll probably want to restrict the IP addresses that can access the API, but if you want to get it working quick / dirty to test out if that change fixes it you can set it to accept all like so (you can also set the range on the ports to accept all ports too, but I didn't do that in this example):您可能希望限制可以访问 API 的 IP 地址,但是如果您想让它快速/肮脏地工作以测试该更改是否修复了它,您可以将其设置为接受所有这样的(您也可以设置端口上的范围也接受所有端口,但在本例中我没有这样做):

在此处输入图片说明

A common cause of the "Malformed Lambda proxy response" error is headers that are not {String: String, ...} key/values pairs. “Malformed Lambda 代理响应”错误的一个常见原因是headers不是{String: String, ...}键/值对。

Since set-cookie headers can and do appear in multiples, they are represented in http.request.callback.response as the set-cookie key having an Array of Strings value instead of a single String .由于set-cookie标头可以而且确实以多个形式出现,因此它们在 http.request.callback.response 中表示为set-cookie键,它具有一个Strings Array值而不是单个String While this works for developers, AWS API Gateway doesn't understand it and throws a "Malformed Lambda proxy response" error.虽然这对开发人员有效,但 AWS API Gateway 不理解它并抛出“格式错误的 Lambda 代理响应”错误。

My solution is to do something like this:我的解决方案是做这样的事情:

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

Note that the ... above does not mean Yada Yada Yada .请注意, ...上面的意思不是Yada Yada Yada It's the ES6 spread operator .它是ES6 扩展运算符

Here's another approach.这是另一种方法。 Configure the mapping template in your API gateway integration request and response.在 API 网关集成请求和响应中配置映射模板。 Go to IntegrationRequest -> MappingTemplate -> select "When there are no templates defined" -> type application/json for content-type.转到 IntegrationRequest -> MappingTemplate -> 选择“当没有定义模板时”-> 为内容类型键入 application/json。 Then you don't have to explicitly send a json.然后您不必显式发送 json。 Even the response you get at your client can be a plain string.甚至您在客户端得到的响应也可以是纯字符串。

The format of your function response is the source of this error.函数响应的格式是此错误的来源。 For API Gateway to handle a Lambda function's response, the response must be JSON in this format:为了让 API Gateway 处理 Lambda 函数的响应,响应必须是以下格式的 JSON:

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

Here's an example function in Node.js with the response correctly formatted:这是 Node.js 中的示例函数,其响应格式正确:

exports.handler = (event, context, callback) => { export.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);

}; };

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

Python 3.7蟒蛇 3.7

Before

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

After

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

If you're just new to AWS and just want your URL working,如果您刚接触 AWS 并且只想让您的 URL 正常工作,

If you haven't created a trigger for your Lambda Function, navigate to the function in Lambda Functions app and create trigger choosing API Gateway.如果您尚未为 Lambda 函数创建触发器,请导航到 Lambda 函数应用程序中的函数并选择 API 网关创建触发器。

Navigate to API Gateway App -> Choose your Particular Lambda's API Gateway (Method execution) -> Click on INTEGRATION Request -> Uncheck "Use Lambda Proxy integration" (check box).导航到 API 网关应用程序 -> 选择您特定的 Lambda 的 API 网关(方法执行)-> 单击集成请求 ->取消选中“使用 Lambda 代理集成” (复选框)。

Then click on " <-Method Execution " & click on Test Client section.然后单击“ <-Method Execution ”并单击“测试客户端”部分。 Provide the options and click test button.提供选项并单击测试按钮。 You should see a success response.您应该会看到成功响应。

If you are still unable to get a success response, create an alias for the correct version (if you have multiple versions in the Lambda Function)如果您仍然无法获得成功响应,请为正确的版本创建别名(如果您在 Lambda 函数中有多个版本)

Pick the URL from the logs and use your POST/GET Tool (Postman) and choose authentication as AWS Signature - provide your authentication keys(AccessKey & SecretKey) in the postman request with AWS Region & Service Name as lambda.从日志中选择 URL 并使用您的 POST/GET 工具(邮递员)并选择身份验证作为 AWS 签名 - 在邮递员请求中提供您的身份验证密钥(访问密钥和秘密密钥),并将 AWS 区域和服务名称作为 lambda。

PS : This may only help beginners and may be irrelevant to others. PS:这可能只对初学者有帮助,对其他人可能无关紧要。

您返回的正文很可能是JSON<\/code>格式,但 Lambda 代理与 API Gateway 的集成只允许使用STRING<\/code>格式。

所以用JSON.stringify()<\/code>包装你的旧响应体。

"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM