V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
cocong
V2EX  ›  Java

为何 RestTemplate 无法定制请求

  •  
  •   cocong ·
    hzh-cocong · 1 天前 · 966 次点击

    我们项目都是配置一个 RestTemplate bean ,然后所有外部请求都用它,现在有个需求的超时时间要求不一样,就得重新定义一个 bean ,又得怼一堆配置,麻烦,直接用 simpleClientHttpRequestFactory 又不能用到连接池,所以为何 RestTemplate 不支持对每个请求定制化,就像事务超时设置 @Transactional(timeout = 3),每个都可以不一样,唯独这个外部请求没有这种功能,就感觉不太合理。

    问了 AI ,可以用下面的方法,但感觉还是太麻烦了,不够简单优雅

    步骤 1:创建一个全局共享的、带连接池的 CloseableHttpClient

    public class PooledRestClient {
    
        private static final CloseableHttpClient httpClient;
    
        static {
            PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
            cm.setMaxTotal(100);
            cm.setDefaultMaxPerRoute(20);
            // 可选:设置空闲连接清理
            httpClient = HttpClients.custom()
                    .setConnectionManager(cm)
                    .evictIdleConnections(60, TimeUnit.SECONDS)
                    .build();
        }
    
        // 核心方法:动态发起请求
        public static ResponseEntity<String> exchange(
                String url,
                HttpMethod method,
                HttpEntity<?> requestEntity,
                Class<String> responseType,
                int connectTimeoutMs,
                int readTimeoutMs) {
    
            HttpComponentsClientHttpRequestFactory factory =
                    new HttpComponentsClientHttpRequestFactory( httpClient);
            factory.setConnectTimeout(connectTimeoutMs);
            factory.setReadTimeout(readTimeoutMs);
    
            RestTemplate restTemplate = new RestTemplate(factory);
            return restTemplate.exchange(url, method, requestEntity, responseType);
        }
    }
    

    步骤 2:在业务代码中直接调用(无需 Spring Bean )

    // 动态构造请求头
    HttpHeaders headers = new HttpHeaders();
    headers.set("Authorization", "Bearer " + token);
    headers.setContentType(MediaType.APPLICATION_JSON);
    
    HttpEntity<String> entity = new HttpEntity<>("{\"key\":\"value\"}", headers);
    
    // 发起带连接池的请求(每次 URL/Token/Body 都可不同)
    ResponseEntity<String> response = PooledRestClient.exchange(
            "https://api.example.com/v1/data",
            HttpMethod.POST,
            entity,
            String.class,
            3000,   // connect timeout
            10000   // read timeout
    );
    
    8 条回复    2025-11-07 18:29:16 +08:00
    xtreme1
        1
    xtreme1  
       1 天前
    用 WebClient, 可以拿到一个 CompletableFuture
    potatowish
        2
    potatowish  
       1 天前 via iPhone
    spring 5.0 webclient 就可以吧,每个请求可以单独设置超时时间
    momo31
        3
    momo31  
       1 天前
    直接用 okhttp 呢
    tedzhou1221
        4
    tedzhou1221  
       1 天前
    我们之前的项目改用 Forest http
    doppler
        5
    doppler  
       1 天前
    用 webclient 加 timeout 操作符
    nananqujava
        6
    nananqujava  
       1 天前
    Forest 好用 https://forest.kim/
    Need4more
        7
    Need4more  
       21 小时 13 分钟前
    你这太罗嗦了,用 RestTemplateBuilder

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder
    .setConnectTimeout(Duration.ofSeconds(5))
    .setReadTimeout(Duration.ofSeconds(5))
    .build();
    }
    looo
        8
    looo  
       20 小时 27 分钟前
    @Need4more 我之前项目也是这么搞,一个三方一个 bean ,每一家的接口超时不一样
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   2748 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 06:56 · PVG 14:56 · LAX 22:56 · JFK 01:56
    ♥ Do have faith in what you're doing.