首页 文章

从AWS-API网关发布到Lambda

提问于
浏览
8

我有一个简单的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; }
}

2 回答

  • 15

    在API网关中使用Lambda代理集成时, FunctionHandler 的第一个参数不是POST的主体,而是另一个API网关创建的对象,让我们调用 LambdaRequest . 尝试对示例代码进行这些更改 . 加:

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

    将处理程序原型更改为:

    public LambdaResponse FunctionHandler(LambdaRequest req, ILambdaContext context)
    

    并在 FunctionHandler 内添加:

    ZipRequest input = JsonConvert.DeserializeObject<ZipRequest>(req.Body);
    

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

  • 6

    当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
            };
        }
    

相关问题