Apache HttpAsyncClient带请求体重试策略测试失败问题咨询
问题根因
Apache HttpAsyncClient 5.x 内置的DefaultHttpRequestRetryStrategy默认有两个限制导致带Body的请求无法重试:
- 默认仅对被标记为幂等的请求(无请求体的GET/HEAD等请求默认被判定为幂等)执行重试,带请求体的PUT/POST等请求默认不会被判定为可重试请求,避免非幂等请求重复提交产生数据副作用
- 即使是幂等的PUT请求,只要携带请求体,默认会额外校验请求体是否支持重复读取,虽然
SimpleHttpRequest的请求体存储在内存中天然支持重复读取,但默认策略没有开启带缓冲请求体请求的重试开关
解决方案
提供两种可选方案,任选其一即可:
方案1:显式标记请求为幂等
构造请求时添加属性,告知客户端当前请求是幂等的可安全重试:
import org.apache.hc.client5.http.protocol.HttpClientContext val request: SimpleHttpRequest = SimpleRequestBuilder .put(baseUrl) .setPath("/test") .setBody("{}", ContentType.APPLICATION_JSON) // 显式标记请求为幂等,允许重试 .setAttribute(HttpClientContext.REQUEST_ATTR_IDEMPOTENT, java.lang.Boolean.TRUE) .build()
方案2:自定义重试策略,放开校验限制
自定义重试策略类,覆盖默认的重试校验逻辑,按需放开限制:
import org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy import org.apache.hc.core5.http.{HttpRequest, HttpResponse, HttpStatus} import org.apache.hc.core5.http.protocol.HttpContext import org.apache.hc.core5.util.TimeValue import java.io.IOException class CustomHttpRequestRetryStrategy( maxRetries: Int, retryInterval: TimeValue ) extends DefaultHttpRequestRetryStrategy(maxRetries, retryInterval) { // 异常场景重试逻辑 override def retryRequest( request: HttpRequest, exception: IOException, execCount: Int, context: HttpContext ): Boolean = { // 重试次数未超限就允许重试 execCount <= getMaxRetries } // 响应状态码异常重试逻辑 override def retryRequest( response: HttpResponse, execCount: Int, context: HttpContext ): Boolean = { val statusCode = response.getCode // 显式指定429为可重试状态码,可按需扩展其他状态码 if (statusCode == HttpStatus.SC_TOO_MANY_REQUESTS && execCount <= getMaxRetries) { return true } super.retryRequest(response, execCount, context) } }
创建客户端时使用自定义的重试策略即可:
val httpClient: CloseableHttpAsyncClient = HttpAsyncClients.custom() .setRetryStrategy(new CustomHttpRequestRetryStrategy(4, TimeValue.ofMilliseconds(500))) .build()
两种方案修改后重新执行测试,带Body的请求也会触发预期的4次重试,Mock服务端会累计收到5次请求。
内容的提问来源于stack exchange,提问作者Gilberto T.
相关产品推荐
相关产品推荐

