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

最佳实践:如何让自定义RestTemplate自动重试失败的API调用?

实现方案推荐

核心结论

绝对不要在ResponseErrorHandler的handleError()方法中处理重试逻辑:该方法被触发时,HTTP响应的输入流已经被标记为只读、仅可消费一次,在此处发起重试极易出现流已关闭、资源泄漏、请求上下文丢失的问题,该类的设计定位本身就是错误状态解析而非重试编排。

优先选择全局统一处理的方案,避免每个业务API调用处重复编写冗余代码,后期维护成本更低,仅在个别接口有特殊重试规则时再做单独适配。


推荐实现方案

方案1:Spring Retry 注解式实现(优先选择,侵入性最低)

适合需要灵活配置不同接口重试规则的场景,无需修改现有业务逻辑核心代码:

  1. 引入依赖(Spring Boot场景)
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-retry</artifactId>
</dependency>
  1. 启用重试功能:在启动类/配置类上添加@EnableRetry注解
  2. 给需要重试的业务方法添加重试配置:
@Retryable(
    retryFor = [HttpClientErrorException.Unauthorized::class, ResourceAccessException::class],
    maxAttempts = 3,
    backoff = Backoff(delay = 1000, multiplier = 2)
)
fun create(contentRequest: OrderSendXXXDto, accessToken: String): ResponseEntity<OrderXXXResponseDto> {
    // 原有业务逻辑不变
}

// 可选:添加重试全部失败后的降级逻辑
@Recover
fun createFallback(e: Exception, contentRequest: OrderSendXXXDto, accessToken: String): ResponseEntity<OrderXXXResponseDto> {
    // 自定义降级逻辑,比如抛出业务异常、返回默认值等
}

你可以直接在重试触发条件中配置仅当外部API抛出401异常时触发重试,和你现有的token刷新逻辑天然配合。


方案2:ClientHttpRequestInterceptor 全局拦截实现(全量请求统一规则)

适合所有走该RestTemplate的外部API请求都需要统一重试逻辑的场景,完全无需修改业务层代码:

  1. 先配置RestTemplate使用可缓存请求体的工厂,避免重试时请求体丢失:
@Bean
fun restTemplate(): RestTemplate {
    val factory = BufferingClientHttpRequestFactory(SimpleClientHttpRequestFactory())
    val restTemplate = RestTemplate(factory)
    // 注册自定义重试拦截器
    restTemplate.interceptors.add(retryInterceptor())
    // 注册你原有自定义的ExternalApiErrorHandler
    restTemplate.errorHandler = externalApiErrorHandler()
    return restTemplate
}
  1. 编写自定义重试拦截器:
class RetryInterceptor(
    private val xxxAuthService: XXXAuthService
) : ClientHttpRequestInterceptor {
    override fun intercept(
        request: HttpRequest,
        body: ByteArray,
        execution: ClientHttpRequestExecution
    ): ClientHttpResponse {
        var retryCount = 0
        val maxRetry = 3
        while(retryCount < maxRetry) {
            val response = execution.execute(request, body)
            if (response.statusCode != HttpStatus.UNAUTHORIZED 
                || !ExternalApiEnpoint.isExternalApiEndpoint(request.uri.toString())) {
                return response
            }
            // 401场景先刷新token再重试
            xxxAuthService.callLogin()
            retryCount++
            response.close()
        }
        throw RuntimeException("外部API请求重试${maxRetry}次后仍失败")
    }
}

相关检索关键词

  • Spring RestTemplate 全局重试实现
  • Spring Retry 401 Token自动刷新
  • RestTemplate ClientHttpRequestInterceptor 重试逻辑
  • ResponseErrorHandler 重试 流关闭问题
  • Spring RestTemplate 401 自动登录重试

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 00:24:00