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

SpringBoot 3中TestRestTemplate调用返回400接口时触发I/O错误

问题解决:TestRestTemplate调用返回400接口时抛出I/O错误

这个错误的核心原因是默认TestRestTemplate底层的HttpClient重试机制与流式请求(如JSON POST体)冲突:当服务器返回400时,HttpClient尝试重试请求,但因为请求体已经被流式发送,无法重复读取,从而抛出该异常。

解决方案1:自定义TestRestTemplate,禁用重试策略

通过RestTemplateBuilder构建自定义的TestRestTemplate,关闭重试机制:

import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Primary
import org.springframework.http.client.SimpleClientHttpRequestFactory

@Bean
@Primary
fun testRestTemplate(builder: RestTemplateBuilder): TestRestTemplate {
    val requestFactory = SimpleClientHttpRequestFactory().apply {
        setConnectTimeout(5000)
        setReadTimeout(5000)
    }
    return TestRestTemplate(builder.requestFactory { requestFactory }.build())
}

解决方案2:改用exchange方法替代postForEntity

exchange方法对响应的处理更灵活,能避免重试触发的问题:

@Test
fun signIn_InvalidPassword() {
    val headers = HttpHeaders()
    headers.contentType = MediaType.APPLICATION_JSON
    val body = AuthenticationRequest(email = "user@email.com", password = "password")
    val httpRequest: HttpEntity<AuthenticationRequest> = HttpEntity(body, headers)

    val result = testRestTemplate.exchange(
        "/auth/signin",
        HttpMethod.POST,
        httpRequest,
        String::class.java
    )
    assertThat(result.statusCode, equalTo(HttpStatus.BAD_REQUEST))
}

解决方案3:调整响应解析方式

如果服务返回的400响应包含JSON格式的错误信息,可以直接指定对应的错误DTO类作为响应类型,而非String::class.java,这也能避免流式读取的重试冲突:

// 假设你的错误响应DTO类是ValidationErrorResponse
val result = testRestTemplate.postForEntity(
    "/auth/signin",
    httpRequest,
    ValidationErrorResponse::class.java
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 13:57:20