【问题标题】:AWS lambda api gateway error "Malformed Lambda proxy response"AWS lambda api 网关错误“格式错误的 Lambda 代理响应”
【发布时间】:2026-01-29 23:40:02
【问题描述】:

我正在尝试使用 AWS lambda 设置一个 hello world 示例并通过 api 网关为其提供服务。我单击“创建 Lambda 函数”,它设置了 api 网关并选择了空白函数选项。我添加了 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 代理响应”。

【问题讨论】:

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


    【解决方案1】:

    通常,当您看到 Malformed Lambda proxy response 时,这意味着您的 Lambda 函数的响应与 API Gateway 期望的格式不匹配,如下所示

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

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

    另外,如果您看到间歇性的Malformed Lambda proxy response,这可能意味着对您的 Lambda 函数的请求已被 Lambda 限制,您需要请求增加 Lambda 函数的并发执行限制。

    【讨论】:

    【解决方案2】:

    如果使用 lambda 作为代理,那么响应格式应该是

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

    注意:正文应字符串化

    【讨论】:

    • 如果“response”是您的对象的名称,则使用 JSON.stringify(response) 不起作用。像这样离开它对我有用。 callback(null,response);
    • @Neo 您不需要对响应对象进行字符串化。您需要将响应对象的正文键内的数据字符串化
    • 出于好奇 - 为什么需要对身体进行字符串化?这是我一直在做的事情的一个问题,这让我很困惑 - 谢谢
    • 其中,只有statusCode 需要来自 API Gateway 的调用才能成功。
    • 确保身体被字符串化为我工作。非常感谢 +1
    【解决方案3】:

    是的,所以我认为这是因为您实际上并没有在那里返回正确的 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'}))
    

    【讨论】:

    • 现在,如果我们使用 Access-Control-Allow-Credentials 值为 true,我们不能将 'Access-Control-Allow-Origin' 值保留为 '*'
    • 我观察到它只支持一个 Origin: headers: { "Access-Control-Allow-Origin" : ">", "Access-Control-Allow-Credentials" : true / / cookie 需要,HTTPS 授权标头 },
    【解决方案4】:

    对于 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': ''
    

    【讨论】:

      【解决方案5】:

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

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

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

      > 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 或回调返回方法。

      【讨论】:

      • 我做了完全相同的事情 - 删除了 async,因为我删除了 await 并开始遇到完全相同的问题!你的帖子真的很有帮助。谢谢!
      【解决方案6】:

      来自AWS docs

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

      【讨论】:

        【解决方案7】:

        我已经尝试了上述所有建议,但在 body 值不是 String 时不起作用

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

        【讨论】:

          【解决方案8】:

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

          来自 lambda 的响应将是:

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

          来自 api 网关的响应将是:

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

          【讨论】:

          • 天啊,非常感谢,在数小时试图弄清楚如何在响应中获取标题之后,您才救了我。我尝试了纯 JSON,但没有用。我试过键值对,没有用。字典是要走的路!谢谢!
          【解决方案9】:

          一个非常非常特殊的情况,如果你直接传递标头,你就有机会得到这个标头:

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

          但是亚马逊需要这个:

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

          【讨论】:

            【解决方案10】:

            对于在响应显示为有效时遇到困难的其他人。这不起作用:

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

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

            【讨论】:

              【解决方案11】:

              如果您将 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
              }
              

              【讨论】:

                【解决方案12】:

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

                【讨论】:

                  【解决方案13】:

                  如果上述方法对任何人都不起作用,尽管正确设置了响应变量,我还是遇到了这个错误。

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

                  您可能希望限制可以访问 API 的 IP 地址,但如果您想让它快速/肮脏地工作以测试该更改是否修复了它,您可以将其设置为接受所有这些(您可以还将端口的范围设置为也接受所有端口,但在此示例中我没有这样做):

                  【讨论】:

                    【解决方案14】:

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

                    由于set-cookie 标头可以并且确实以多个形式出现,因此它们被表示 在 http.request.callback.response 作为 set-cookie 键具有 ArrayStrings 值而不是单个String。虽然这适用于开发人员,但 AWS API Gateway 不理解并抛出“格式错误的 Lambda 代理响应” 错误。

                    我的解决方案是这样做:

                    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

                    【讨论】:

                      【解决方案15】:

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

                      【讨论】:

                        【解决方案16】:

                        您的函数响应格式是此错误的根源。要让 API Gateway 处理 Lambda 函数的响应,响应必须是以下格式的 JSON:

                        { “isBase64Encoded”:真|假, “状态代码”:http状态代码, “标题”:{“标题名称”:“标题值”,...}, “身体”: ”...” }

                        这是 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/

                        【讨论】:

                          【解决方案17】:

                          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
                          }
                          

                          【讨论】:

                            【解决方案18】:

                            如果您是 AWS 的新手,只想让您的 URL 正常工作,

                            如果您尚未为 Lambda 函数创建触发器,请导航到 Lambda 函数应用程序中的函数并选择 API Gateway 创建触发器。

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

                            然后点击“”并点击测试客户端部分。提供选项并单击测试按钮。您应该会看到成功响应。

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

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

                            P.S : 这可能只对初学者有帮助,可能对其他人无关。

                            【讨论】:

                              【解决方案19】:

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

                              所以用 JSON.stringify() 包裹你的旧响应正文。

                              【讨论】:

                                最近更新 更多