Spring REST控制器接收Facebook Messenger API JSON输入显示null的问题排查
我之前调试Facebook Messenger Webhook时也遇到过类似的情况,咱们来一步步分析问题所在,以及对应的解决办法:
核心原因分析
你看到日志输出"Received event null",主要是因为Spring没有正确将请求体的JSON数据绑定到onWebhookEvent方法的参数上,常见的触发场景有这几个:
缺少
@RequestBody注解
Spring MVC默认不会自动将POST请求的JSON请求体绑定到方法参数上,必须显式添加@RequestBody注解,告诉框架要从请求体中读取数据并绑定到参数。如果没加这个注解,参数就会是null。参数类型不匹配(误解了JSON的接收方式)
你提到“原本以为它会以字符串形式传入”,这个想法本身没问题,但如果没有正确配置,Spring无法将JSON请求体转换为字符串;更常见的误区是直接用自定义对象接收,但对象结构和JSON不匹配,导致反序列化失败,最终参数为null。请求头
Content-Type不正确
Facebook Messenger发送Webhook请求时,会自动设置Content-Type: application/json,但如果你自己测试时(比如用Postman)没设置这个头,Spring会认为请求体不是JSON格式,不会进行解析,导致参数为null。Jackson序列化配置缺失
Spring依赖Jackson来处理JSON的序列化/反序列化,如果你的项目中缺少Jackson相关依赖(比如Spring Boot项目默认包含,但普通Spring项目需要手动引入),也会导致无法解析JSON,参数为null。
具体解决办法
1. 给方法参数添加@RequestBody注解
这是最基础也是最常见的修复方式,不管你是用字符串接收还是自定义对象接收,都需要加上这个注解:
方式一:以字符串形式接收JSON
如果只是想先打印原始JSON内容,直接用String类型参数即可:
@RestController @RequestMapping("/webhook") public class WebhookController { private static final Logger logger = LoggerFactory.getLogger(WebhookController.class); @PostMapping public ResponseEntity<String> onWebhookEvent(@RequestBody String eventBody) { logger.info("Received event {}", eventBody); // 后续可以将字符串转为JSON对象处理 return ResponseEntity.ok("Success"); } }
方式二:用自定义POJO接收(推荐)
为了更方便地处理Webhook事件,建议根据Facebook Messenger的事件结构定义对应的POJO类,让Spring自动完成反序列化:
首先定义事件结构类(示例,根据实际需要补充字段):
import lombok.Data; import java.util.List; @Data // 用Lombok简化getter/setter,也可以手动写 public class WebhookEvent { private String object; private List<Entry> entry; @Data public static class Entry { private String id; private Long time; private List<Messaging> messaging; } @Data public static class Messaging { private Sender sender; private Recipient recipient; private Long timestamp; private Message message; } @Data public static class Sender { private String id; } @Data public static class Recipient { private String id; } @Data public static class Message { private String mid; private String text; } }
然后在控制器中使用这个POJO:
@PostMapping public ResponseEntity<String> onWebhookEvent(@RequestBody WebhookEvent event) { logger.info("Received event: object={}, entry count={}", event.getObject(), event.getEntry().size()); // 处理具体的消息逻辑,比如获取用户发送的文本 event.getEntry().forEach(entry -> { entry.getMessaging().forEach(messaging -> { if (messaging.getMessage() != null) { logger.info("User {} sent message: {}", messaging.getSender().getId(), messaging.getMessage().getText()); } }); }); return ResponseEntity.ok("Success"); }
2. 确保请求头Content-Type正确
如果你自己测试Webhook,一定要在请求头中设置Content-Type: application/json,否则Spring不会解析请求体的JSON数据。比如用Postman测试时,在Headers标签添加这个键值对即可。
3. 确认Jackson依赖存在
如果是普通Spring项目(非Spring Boot),需要在pom.xml(Maven)或build.gradle(Gradle)中添加Jackson依赖:
- Maven:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> <!-- 用最新稳定版 --> </dependency>
- Gradle:
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
Spring Boot项目则无需手动添加,因为spring-boot-starter-web已经包含了Jackson依赖。
测试验证
完成上述配置后,你可以用Facebook提供的Webhook测试工具,或者自己构造JSON请求发送到/webhook端点,此时日志应该能正确打印出接收到的事件内容,而不是null了。
内容的提问来源于stack exchange,提问作者tenticon

