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

如何测试Spring WebClient的onStatus方法?模拟状态码与获取响应

问题解答

一、WebClient onStatus 机制说明

  • onStatus 是WebClient用来自定义特定HTTP状态码处理逻辑的方法:
    1. 第一个参数是状态匹配谓词(比如HttpStatus.INTERNAL_SERVER_ERROR::equals),当WebClient收到的响应状态码满足这个条件时,触发第二个参数的处理函数。
    2. 响应的状态码和完整响应对象(ClientResponse)来自实际HTTP调用返回的结果,onStatus的第二个参数函数会接收这个ClientResponse,你可以从中获取状态码、响应体、响应头等信息。
    3. 该函数返回的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是否正确读取了响应的其他信息(比如响应头),可以:

  1. 在MockWebServer中添加响应头:
    mockWebServer.enqueue(new MockResponse()
            .setResponseCode(500)
            .setHeader("X-Error-Code", "DB-001")
            .setBody("数据库连接失败"));
    
  2. 修改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))))
    
  3. 在测试中验证异常消息包含响应头内容即可。

四、常见注意事项

  • 如果你只处理了500状态,其他错误状态(比如404、400)会触发WebClient的默认行为——抛出WebClientResponseException,如果需要统一处理所有错误状态,可以用HttpStatus::isError作为谓词:
    .onStatus(HttpStatus::isError, resp -> resp.bodyToMono(String.class).map(Exception::new))
    
  • onStatus的处理函数必须返回Mono<Throwable>,不能直接抛出异常,否则会破坏响应式流的异步逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 04:55:33