如何测试Spring WebClient的onStatus方法?模拟状态码与获取响应
问题解答
一、WebClient onStatus 机制说明
onStatus是WebClient用来自定义特定HTTP状态码处理逻辑的方法:- 第一个参数是状态匹配谓词(比如
HttpStatus.INTERNAL_SERVER_ERROR::equals),当WebClient收到的响应状态码满足这个条件时,触发第二个参数的处理函数。 - 响应的状态码和完整响应对象(
ClientResponse)来自实际HTTP调用返回的结果,onStatus的第二个参数函数会接收这个ClientResponse,你可以从中获取状态码、响应体、响应头等信息。 - 该函数返回的
Mono<Throwable>会替换WebClient原本的响应流——也就是说,当状态匹配时,WebClient不会返回正常响应,而是抛出这个异常。
- 第一个参数是状态匹配谓词(比如
二、模拟特定状态码并编写测试
可以用Spring官方推荐的MockWebServer(属于Spring Boot Test依赖)来模拟HTTP响应,步骤如下:
1. 准备测试环境
先初始化MockWebServer和指向该服务器的WebClient:
import okhttp3.mockwebserver.MockWebServer; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.http.HttpStatus; import reactor.test.StepVerifier; public class WebClientOnStatusTest { private MockWebServer mockWebServer; private WebClient webClient; @BeforeEach void setUp() { mockWebServer = new MockWebServer(); webClient = WebClient.builder() .baseUrl(mockWebServer.url("/").toString()) .build(); } @AfterEach void tearDown() throws Exception { mockWebServer.shutdown(); }
2. 测试500状态的处理逻辑
模拟返回500状态码和响应体,验证onStatus是否正确抛出包含响应体的异常:
@Test void when500Response_thenThrowExceptionWithResponseBody() { // 配置MockWebServer返回500状态和自定义响应体 mockWebServer.enqueue(new MockResponse() .setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value()) .setBody("数据库连接失败")); // 执行WebClient调用 var responseMono = webClient.post() .uri("/some-resource") .retrieve() .onStatus(HttpStatus.INTERNAL_SERVER_ERROR::equals, resp -> resp.bodyToMono(String.class).map(Exception::new)) .bodyToMono(Void.class); // 替换为实际业务的响应类型 // 验证异常是否符合预期 StepVerifier.create(responseMono) .expectErrorMatches(throwable -> throwable instanceof Exception && throwable.getMessage().equals("数据库连接失败")) .verify(); }
三、如何验证onStatus中的响应处理
如果你需要确认onStatus是否正确读取了响应的其他信息(比如响应头),可以:
- 在MockWebServer中添加响应头:
mockWebServer.enqueue(new MockResponse() .setResponseCode(500) .setHeader("X-Error-Code", "DB-001") .setBody("数据库连接失败")); - 修改
onStatus的处理逻辑,把响应头信息加入异常:.onStatus(HttpStatus.INTERNAL_SERVER_ERROR::equals, resp -> resp.bodyToMono(String.class) .map(body -> new Exception(body + ", 错误码: " + resp.headers().header("X-Error-Code").get(0)))) - 在测试中验证异常消息包含响应头内容即可。
四、常见注意事项
- 如果你只处理了500状态,其他错误状态(比如404、400)会触发WebClient的默认行为——抛出
WebClientResponseException,如果需要统一处理所有错误状态,可以用HttpStatus::isError作为谓词:.onStatus(HttpStatus::isError, resp -> resp.bodyToMono(String.class).map(Exception::new)) onStatus的处理函数必须返回Mono<Throwable>,不能直接抛出异常,否则会破坏响应式流的异步逻辑。
内容的提问来源于stack exchange,提问作者hypernuggets
相关产品推荐
相关产品推荐

