You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Stripe Webhook的dataObjectDeserializer.object返回空Optional?

问题原因及解决方法

可能的原因

  1. 库与API版本不兼容
    Stripe Java SDK 24.12.0对应的API版本是2024-06-20,如果你的Stripe后台Webhook端点配置的API版本和这个不一致,会导致数据结构不匹配,反序列化失败,最终deserialiser.object返回空Optional。

  2. 错误的反序列化判断逻辑
    你当前代码直接判断deserialiser.object != null,但正确的流程应该先检查deserialiser.isSuccess()——如果反序列化失败,object必然是空,且可以通过deserialiser.error获取具体错误信息,这能帮你定位问题。

  3. 请求体处理问题
    Spring Boot默认的@RequestBody String body可能会对请求体做隐性修改(比如编码转换、多余转义),虽然签名验证通过了,但可能破坏了Stripe SDK反序列化所需的原始JSON结构。

解决步骤

1. 确认API版本匹配

登录Stripe后台,检查Webhook端点的API版本是否与SDK版本对应(24.12.0对应2024-06-20),如果不一致,要么升级/降级SDK,要么修改Webhook的API版本。

2. 修正反序列化逻辑

使用Stripe SDK提供的正确方式提取Charge对象,示例代码如下:

@ResponseBody
@PostMapping("/stripewebhook")
fun index(
    @RequestHeader(value = "Stripe-Signature") stripeSecret: String,
    @RequestBody body: String
): HttpStatus = try {
    val event = Webhook.constructEvent(body, stripeSecret, ourEndpointSecret)
    val deserializer = event.dataObjectDeserializer

    if (deserializer.isSuccess) {
        when (event.type) {
            "charge.succeeded" -> {
                val charge = deserializer.getObject(Charge::class.java)
                // 处理Charge对象
                receiveReceipt(charge, body)
            }
            else -> {
                log.error("无效的事件类型: ${event.type}")
                HttpStatus.BAD_REQUEST
            }
        }
    } else {
        log.error("Stripe对象反序列化失败: ${deserializer.error}")
        HttpStatus.BAD_REQUEST
    }
} catch (e: SignatureVerificationException) {
    log.error("签名验证失败", e)
    HttpStatus.BAD_REQUEST
} catch (e: JSONException) {
    log.error("请求体解析失败", e)
    HttpStatus.BAD_REQUEST
} catch (e: Exception) {
    log.error("支付处理异常", e)
    HttpStatus.INTERNAL_SERVER_ERROR
}

3. 确保获取原始请求体(可选)

如果上述步骤无效,尝试获取原始字节数组来避免Spring的隐性修改:

@ResponseBody
@PostMapping("/stripewebhook", consumes = [MediaType.APPLICATION_JSON_VALUE])
fun index(
    @RequestHeader(value = "Stripe-Signature") stripeSecret: String,
    request: HttpServletRequest
): HttpStatus = try {
    val body = request.inputStream.bufferedReader().use { it.readText() }
    // 后续逻辑同上
} catch (e: Exception) {
    // 异常处理
}

内容的提问来源于stack exchange,提问作者Michael NGV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 11:05:28