AWS SNS触发Lambda时消息内容为空,邮件却收到完整内容求助
问题:SNS触发Docker部署的C# Lambda时,SNSEvent.SNSMessage对象为空值
我有一个用C#编写、以Docker容器形式部署的Lambda函数,由SNS主题触发。该主题有两个订阅:我的邮箱和这个Lambda函数。
触发主题发送事件消息时,我能收到包含完整JSON结构的邮件,Lambda也会被触发,但Lambda打印Amazon.Lambda.SNSEvents.SNSEvent.SNSMessage对象时,所有字段都是空值或默认时间(1/1/0001 12:00:00 AM),导致后续反序列化消息内容时抛出异常。
但把邮件里的JSON内容复制到Lambda控制台的「测试」标签页运行时,Lambda完全正常无错误。我原本以为SNS触发器会自动将触发消息的内容传递给Lambda函数,实际却不是这样,想知道问题原因和解决办法。
编辑
为便于排查,以下是我的Lambda完整入口类,Dockerfile中指定的Lambda入口点为MySNSEventHandler()方法:
using Amazon.Lambda.Core; using Amazon.Lambda.SNSEvents; using Microsoft.Extensions.DependencyInjection; using MySNSEventListener.EventHandlers; using MySNSEventListener.Interfaces; // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] namespace MySNSEventListener; public class MySNSEventHandler { /// <summary> /// This function is the entry point for the Lambda. It creates a new MySNSEventFactory and passes it to another method where the actual functionality lives. /// These are separated out so that the functionality is testable by the Moq framework, as we need to be able to pass something in if we want to mock it within the tested function. /// </summary> /// <param name="incomingMessage"></param> /// <param name="context"></param> /// <returns></returns> public async Task MySNSEventHandler(SNSEvent.SNSMessage incomingMessage, ILambdaContext context) { IMySNSEventFactory eventFactory = new MySNSEventFactory(); await MySNSEventHandlerWithFactory(eventFactory, incomingMessage, context); } /// <summary> /// Uses the passed in MySNSEventFactory to create an MySNSEvent and then make that event execute its own functionality. /// </summary> /// <param name="MySNSEventFactory"></param> /// <param name="incomingMessage"></param> /// <param name="context"></param> public async Task MySNSEventHandlerWithFactory(IMySNSEventFactory MySNSEventFactory, SNSEvent.SNSMessage incomingMessage, ILambdaContext context) { if (incomingMessage != null) { Console.WriteLine("Incoming SNS Message:"); Console.WriteLine($"\tType: {incomingMessage.Type}"); Console.WriteLine($"\tMessageId: {incomingMessage.MessageId}"); Console.WriteLine($"\tTopicArn: {incomingMessage.TopicArn}"); Console.WriteLine($"\tMessage: {incomingMessage.Message}"); Console.WriteLine($"\tTimeStamp: {incomingMessage.Timestamp}"); Console.WriteLine($"\tSignatureVersion: {incomingMessage.SignatureVersion}"); Console.WriteLine($"\tSignature: {incomingMessage.Signature}"); Console.WriteLine($"\tUnsubscribeUrl: {incomingMessage.UnsubscribeUrl}"); IMySNSEventHandler MySNSEvent = MySNSEventFactory.GetMySNSEvent(_lambdaHttpClientManager, incomingMessage); await MySNSEvent.PerformEventActionAsync(); } else { Console.WriteLine("Incoming message was null."); } } /// From this line until the end of this class, this code was written to enable proper mocking and dependency injection. private static IServiceProvider _services = default!; private static ILambdaHttpClientManager _lambdaHttpClientManager = default!; public MySNSEventHandler() { ConfigureServices(); } public MySNSEventHandler(ILambdaHttpClientManager lambdaHttpClientManager) { _lambdaHttpClientManager = lambdaHttpClientManager; } private void ConfigureServices() { var _host = LambdaHostManager.GetLambdaHostManager().CreateHostBuilder(); _services = _host.Build().Services; _lambdaHttpClientManager = new LambdaHttpClientManager(_services.GetService<IHttpClientFactory>())!; } // This ends the code to enable dependency injection. }
当Lambda被SNS触发时,输出如下:
Incoming SNS Message: Type: MessageId: TopicArn: Message: TimeStamp: 1/1/0001 12:00:00 AM SignatureVersion: Signature: UnsubscribeUrl:
解决方案
问题原因
SNS触发Lambda时,传递的是完整的SNSEvent对象,而非直接的SNSEvent.SNSMessage。你的入口方法参数直接声明为SNSEvent.SNSMessage,序列化器无法解析外层的事件结构,只能生成一个默认的空对象,导致所有字段为空或取默认值。
解决步骤
- 修改入口方法的参数类型为
SNSEvent - 在方法内部从
SNSEvent.Records集合中提取每个记录的Sns属性,这才是实际的SNS消息对象
修改后的入口方法示例
public async Task MySNSEventHandler(SNSEvent incomingEvent, ILambdaContext context) { IMySNSEventFactory eventFactory = new MySNSEventFactory(); // 遍历SNS传递的所有记录(支持批量消息) foreach (var record in incomingEvent.Records) { var incomingMessage = record.Sns; await MySNSEventHandlerWithFactory(eventFactory, incomingMessage, context); } }
修改后,Lambda就能正确解析SNS传递的完整事件结构,提取到有效的消息内容,字段值不再为空。
内容的提问来源于stack exchange,提问作者Catachan
相关产品推荐
相关产品推荐

