簡體   English   中英

AWS lambda api 網關錯誤“格式錯誤的 Lambda 代理響應”

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

我正在嘗試使用 AWS lambda 設置一個 hello world 示例並通過 api 網關為其提供服務。 我單擊“創建 Lambda 函數”,它設置了 api 網關並選擇了空白函數選項。 我添加了AWS 網關入門指南中的 lambda 函數:

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

問題是當我向它發出 GET 請求時,它會返回 502 響應{ "message": "Internal server error" } 並且日志顯示“由於配置錯誤,執行失敗:格式錯誤的 Lambda 代理響應”。

通常,當您看到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 函數的並發執行限制。

如果 lambda 用作代理,則響應格式應為

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

注意:正文應該是字符串化的

是的,所以我認為這是因為您實際上並沒有在那里返回正確的 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'}))

對於 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': ''

來自AWS 文檔

在 Node.js 的 Lambda 函數中,要返回成功的響應,請調用 callback(null, {"statusCode": 200, "body": "results"})。 要拋出異常,請調用 callback(new Error('internal server error'))。 對於客戶端錯誤,例如缺少必需的參數,您可以調用 callback(null, {"statusCode": 400, "body": "Missing parameters of ..."}) 返回錯誤而不拋出例外。

我已經嘗試了以上所有建議,但是當body值不是String時它不起作用

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

只是一段.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! :)"}

我遇到了這個問題,它源於一個看起來完全沒問題的無效處理程序代碼:

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

一個非常特殊的情況,如果您直接傳遞標頭,則有可能擁有此標頭:

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

但亞馬遜需要這個:

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

對於在響應似乎有效時掙扎的其他任何人。 這不起作用:

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

此外,似乎不允許在響應對象上存在額外的鍵。

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

我遇到此錯誤是因為我不小心從 CloudFormation AWS::Serverless::Api 資源中刪除了變量 ServerlessExpressLambdaFunctionName。 這里的上下文是https://github.com/awslabs/aws-serverless-express “使用現有的 Node.js 應用程序框架在 AWS Lambda 和 Amazon API 網關之上運行無服務器應用程序和 REST API”

如果上述內容對任何人都不起作用,盡管正確設置了響應變量,但我還是遇到了這個錯誤。

我正在我的函數中調用 RDS 數據庫。 事實證明,導致問題的原因是該數據庫上的安全組規則(入站)。

您可能希望限制可以訪問 API 的 IP 地址,但是如果您想讓它快速/骯臟地工作以測試該更改是否修復了它,您可以將其設置為接受所有這樣的(您也可以設置端口上的范圍也接受所有端口,但在本例中我沒有這樣做):

在此處輸入圖片說明

“Malformed Lambda 代理響應”錯誤的一個常見原因是headers不是{String: String, ...}鍵/值對。

由於set-cookie標頭可以而且確實以多個形式出現,因此它們在 http.request.callback.response 中表示為set-cookie鍵,它具有一個Strings Array值而不是單個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 擴展運算符

這是另一種方法。 在 API 網關集成請求和響應中配置映射模板。 轉到 IntegrationRequest -> MappingTemplate -> 選擇“當沒有定義模板時”-> 為內容類型鍵入 application/json。 然后您不必顯式發送 json。 甚至您在客戶端得到的響應也可以是純字符串。

函數響應的格式是此錯誤的來源。 為了讓 API Gateway 處理 Lambda 函數的響應,響應必須是以下格式的 JSON:

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

這是 Node.js 中的示例函數,其響應格式正確:

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

};

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

蟒蛇 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
}

如果您剛接觸 AWS 並且只想讓您的 URL 正常工作,

如果您尚未為 Lambda 函數創建觸發器,請導航到 Lambda 函數應用程序中的函數並選擇 API 網關創建觸發器。

導航到 API 網關應用程序 -> 選擇您特定的 Lambda 的 API 網關(方法執行)-> 單擊集成請求 ->取消選中“使用 Lambda 代理集成” (復選框)。

然后單擊“ <-Method Execution ”並單擊“測試客戶端”部分。 提供選項並單擊測試按鈕。 您應該會看到成功響應。

如果您仍然無法獲得成功響應,請為正確的版本創建別名(如果您在 Lambda 函數中有多個版本)

從日志中選擇 URL 並使用您的 POST/GET 工具(郵遞員)並選擇身份驗證作為 AWS 簽名 - 在郵遞員請求中提供您的身份驗證密鑰(訪問密鑰和秘密密鑰),並將 AWS 區域和服務名稱作為 lambda。

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