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

如何在不使用.block()时让WebClient处理Google Recaptcha返回错误

问题描述

Google Recaptcha API的所有请求都会返回200 OK状态码——哪怕密钥错误或验证失败也是如此:

错误返回示例:

{
    "success": false,
    "error-codes": [
        "invalid-input-secret"
    ]
}

成功返回示例:

{
   "success": true,
   "challenge_ts": "2023-09-13T19:04:58Z",
   "hostname": "qua.url.fr",
   "score": 0.9,
   "action": "getAccountWithCharacterCode"
}

现有WebClient调用代码如下:

googleReCaptchaWebClient.post()
        .uri(uriBuilder -> uriBuilder
            .path("siteverify")
            .queryParam("secret", googleReCaptchaSecret)
            .queryParam("response", reCaptcha).build())
            .retrieve()
            .bodyToMono(ReCaptchaResponse.class);

需要修改这段代码,让它不用调用.block()就能在验证失败时抛出异常。之前试过.exchangeToMono(clientResponse -> {}),但没找到避免.block()的方法。


解决方案

你不需要用exchangeToMono,只需在拿到响应体后添加业务校验逻辑,利用Reactor的响应式操作符抛出异常即可——这样订阅Mono时会自动触发异常,完全不需要.block()。

1. 定义验证失败的异常类(可选,也可复用现有异常)

public class ReCaptchaValidationException extends RuntimeException {
    public ReCaptchaValidationException(String message) {
        super(message);
    }
}

2. 修改WebClient调用逻辑

用flatMap操作符判断响应的success字段,验证失败时通过Mono.error()抛出异常:

googleReCaptchaWebClient.post()
        .uri(uriBuilder -> uriBuilder
                .path("siteverify")
                .queryParam("secret", googleReCaptchaSecret)
                .queryParam("response", reCaptcha)
                .build())
        .retrieve()
        .bodyToMono(ReCaptchaResponse.class)
        .flatMap(response -> {
            if (response.isSuccess()) {
                // 验证成功,直接返回响应
                return Mono.just(response);
            } else {
                // 验证失败,拼接错误信息并抛出异常
                String errorMessage = String.format("ReCaptcha验证失败,错误码:%s", 
                    String.join(", ", response.getErrorCodes()));
                return Mono.error(new ReCaptchaValidationException(errorMessage));
            }
        });

关键说明

  • 响应式流中,Mono.error()会将异常信号注入流中,当订阅这个Mono时,异常会被触发,上层可以通过.onErrorXXX()系列操作符处理,完全符合响应式编程的非阻塞流程。
  • 如果你不需要保留原响应对象,也可以用map替代flatMap,但flatMap更灵活(比如后续需要执行异步操作的场景)。
  • 因为API始终返回200,retrieve()已经足够处理响应体,不需要用exchangeToMono去处理状态码。

内容的提问来源于stack exchange,提问作者Tyali Nexi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 22:22:43