从AWS-API网关发布到Lambda

时间:2017-02-08 14:26:57

标签: c# amazon-web-services aws-lambda aws-api-gateway

我有一个简单的C#Aws Lambda函数,它成功通过Lambda控制台测试进行测试但是如果从API网关(我从Lambda触发器选项生成)调用了502(Bad Gateway)失败,并且如果我使用postman。(这个初始函数具有开放访问权限(无安全性))

// request header
    Content-Type: application/json

//  request body
    {
        "userid":22,
        "files":["File1","File2","File3","File4"]
    }

我在日志中遇到的错误是:

Wed Feb 08 14:14:54 UTC 2017 : Endpoint response body before transformations: {
  "errorType": "NullReferenceException",
  "errorMessage": "Object reference not set to an instance of an object.",
  "stackTrace": [
    "at blahblahmynamespace.Function.FunctionHandler(ZipRequest input, ILambdaContext context)",
    "at lambda_method(Closure , Stream , Stream , ContextInfo )"
  ]
}

似乎没有将发布的对象传递给lambda输入参数。

以下代码

// Lambda function
     public LambdaResponse FunctionHandler(ZipRequest input, ILambdaContext context)
        {
            try
            {
                var logger = context.Logger;
                var headers = new Dictionary<string, string>();

                if (input == null || input.files.Count == 0)
                {
                    logger.LogLine($"input was null");
                    headers.Add("testheader", "ohdear");
                    return new LambdaResponse { body = "fail", headers = headers, statusCode = HttpStatusCode.BadRequest };
                }
                else
                {
                    logger.LogLine($"recieved request from user{input?.userid}");
                    logger.LogLine($"recieved {input?.files?.Count} items to zip");
                    headers.Add("testheader", "yeah");
                    return new LambdaResponse { body = "hurrah", headers = headers, statusCode = HttpStatusCode.OK };
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

// Lambda响应/ ZipRequest类

public class LambdaResponse
{

    public HttpStatusCode statusCode { get; set; }
    public Dictionary<string, string> headers { get; set; }
    public string body { get; set; }
}
public class ZipRequest
{
    public int userid { get; set; }
    public IList<string> files { get; set; }
}

3 个答案:

答案 0 :(得分:17)

当OP提出问题时,这可能不可用,但是当使用API​​网关调用Lambda函数时,会提供特定的响应对象。

如前文档Api Gateway Simple Proxy for Lambda Input Format中所述,API网关将输入参数包装在一个相当详细的包装器中。它还需要一个类似的详细响应对象。

但是,没有必要创建自定义请求和响应对象。 AWS团队提供Amazon.Lambda.APIGatewayEvents库,该库也可在NuGet上使用。该库包含现成的APIGatewayProxyRequestAPIGatewayProxyResponse个对象。

仍然需要手动反序列化请求的Body,因为它是字符串,而不是JSON对象。我认为这是为了灵活性吗?

示例函数可能如下所示。它是AWS工具提供的默认功能的修改:

    public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
    {
        var bodyString = request?.Body;

        if (!string.IsNullOrEmpty(bodyString))
        {
            dynamic body = JsonConvert.DeserializeObject(bodyString);

            if (body.input != null)
            {
                body.input = body.input?.ToString().ToUpper();

                return new APIGatewayProxyResponse
                {
                    StatusCode = 200,
                    Body = JsonConvert.SerializeObject(body)
                };
            }
        }

        return new APIGatewayProxyResponse
        {
            StatusCode = 200
        };
    }

答案 1 :(得分:6)

在API网关中使用Lambda代理集成时,FunctionHandler的第一个参数不是POST的主体,而是另一个API网关创建的对象,它可以调用{{1} }。尝试对示例代码进行这些更改。添加:

LambdaRequest

将处理程序原型更改为:

public class LambdaRequest
{
   public string body { get; set; }
}

public LambdaResponse FunctionHandler(LambdaRequest req, ILambdaContext context) 内添加:

FunctionHandler

完整的LambdaRequest对象记录在AWS文档中的Input Format of a Lambda Function for Proxy Integration下,包含HTTP标头,HTTP方法,查询字符串,正文和其他一些内容。

答案 2 :(得分:0)

我还浪费了很多时间试图获取Get方法中传递的“路径参数”。例如,如果您使用的路径为

/ appsetting / 123

...那么您将需要配置类似

enter image description here

通过将资源“ appid”指定为{appid},它告诉API网关将其捕获为路径变量。

我发现的一个关键发现是,通过在POST类型操作的正文中发布,我的Lambda可以正常工作。阅读其他一些线程,然后发现我可以通过以下方式将path变量转换为GET操作的主体:

  1. 选择GET值(如图)
  2. 点击集成请求
  3. 如下所示创建映射模板

enter image description here

现在,当我进行测试时,我只能插入我的appid值并获得正确的结果。希望这对某人有帮助。