如何在不使用.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
相关产品推荐
相关产品推荐

