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

如何为Vert.x HTTP Web Client配置缓存?附Apache HttpClient示例

如何为Vert.x HTTP Web Client配置连接池与缓存

我懂你——习惯了Apache HttpClient那套直观的连接池配置,现在想在Vert.x HTTP Web Client里实现类似的功能对吧?别慌,Vert.x这边也有对应的配置方式,甚至能轻松扩展出HTTP缓存能力,咱们一步步来拆解:

一、先搞定连接池配置(对应Apache的PoolingHttpClientConnectionManager)

Vert.x的Web Client是基于底层的HttpClient实现的,所以连接池的配置其实是在HttpClientOptions里完成的,Web Client会自动复用这个配置。话不多说,直接上代码:

// 初始化HttpClient配置项,对应你之前的连接池参数
HttpClientOptions clientOptions = new HttpClientOptions()
    // 对应Apache的setMaxTotal:设置连接池的全局最大连接数
    .setMaxPoolSize(configuration.getMaxTotalConnections())
    // 对应Apache的setDefaultMaxPerRoute:设置每个目标路由的默认最大连接数
    .setMaxPerRoute(configuration.getDefaultMaxConnectionsPerRoute())
    // 如果你需要给特定主机+端口单独设置连接数上限,就用这个方法,和你之前的setPerRoute逻辑一致
    .setHostMaxConnections(
        configuration.getHost(), 
        configuration.getPort(), 
        configuration.getHostSpecificMaxConnections()
    );

// 创建配置好的HttpClient
HttpClient httpClient = vertx.createHttpClient(clientOptions);

// 基于这个HttpClient创建Web Client,确保复用同一连接池
WebClient webClient = WebClient.create(vertx, new WebClientOptions().setHttpClientOptions(clientOptions));

这里几个关键参数的对应关系给你理清楚:

  • setMaxPoolSize → Apache的setMaxTotal:控制整个连接池的总连接上限
  • setMaxPerRoute → Apache的setDefaultMaxPerRoute:给每个目标域名/端口设置默认的连接数上限
  • setHostMaxConnections → Apache的connectionManager.setMaxPerRoute(httpHost, ...):针对特定主机+端口单独配置连接数

二、实现HTTP响应缓存(类似Apache HttpClient Cache的功能)

Vert.x Web Client本身没有内置HTTP缓存模块,但咱们可以通过自定义拦截器来实现符合RFC 7234规范的缓存逻辑。下面给你一个实用的示例:

1. 先定义缓存存储(生产环境建议换成Redis或Caffeine,这里用本地Map做演示)

// 用ConcurrentHashMap做线程安全的本地缓存
private final ConcurrentMap<String, CacheEntry> responseCache = new ConcurrentHashMap<>();

// 缓存条目类,存储响应内容、头信息和过期时间
static class CacheEntry {
    Buffer body;
    MultiMap headers;
    long expirationTime;

    CacheEntry(Buffer body, MultiMap headers, long expirationTime) {
        this.body = body;
        this.headers = headers;
        this.expirationTime = expirationTime;
    }

    // 判断缓存是否过期
    boolean isExpired() {
        return System.currentTimeMillis() > expirationTime;
    }
}

2. 给Web Client添加缓存拦截器

webClient = WebClient.create(vertx, new WebClientOptions().setHttpClientOptions(clientOptions))
    .addInterceptor(requestContext -> {
        // 只缓存GET请求,POST/PUT这类写请求跳过缓存
        if (requestContext.request().method() != HttpMethod.GET) {
            requestContext.next();
            return;
        }

        // 用请求的绝对URI作为缓存Key
        String cacheKey = requestContext.request().absoluteURI();
        CacheEntry cachedEntry = responseCache.get(cacheKey);

        // 如果缓存存在且未过期,直接返回缓存的响应,不用发真实请求
        if (cachedEntry != null && !cachedEntry.isExpired()) {
            requestContext.response(new HttpResponseImpl(
                requestContext.request(),
                200,
                "OK",
                cachedEntry.headers,
                cachedEntry.body,
                requestContext.request().version()
            ));
            return;
        }

        // 缓存无效或不存在,继续发送请求,然后缓存响应结果
        requestContext.send().onSuccess(response -> {
            // 检查响应是否允许缓存(参考Cache-Control头)
            String cacheControl = response.getHeader("Cache-Control");
            if (cacheControl != null 
                && !cacheControl.contains("no-cache") 
                && !cacheControl.contains("no-store")) {
                
                // 解析max-age计算过期时间,默认10分钟
                long maxAgeMillis = 600_000;
                Matcher maxAgeMatcher = Pattern.compile("max-age=(\\d+)").matcher(cacheControl);
                if (maxAgeMatcher.find()) {
                    maxAgeMillis = Long.parseLong(maxAgeMatcher.group(1)) * 1000;
                }
                long expirationTime = System.currentTimeMillis() + maxAgeMillis;

                // 将响应存入缓存
                responseCache.put(cacheKey, new CacheEntry(response.body(), response.headers(), expirationTime));
            }
            // 将真实响应返回给调用方
            requestContext.response(response);
        }).onFailure(requestContext::fail);
    });

这个拦截器的逻辑很清晰:

  • 只处理GET请求,避免缓存写操作的响应
  • 先检查缓存是否有效,有效就直接返回,减少网络请求
  • 缓存失效时发送真实请求,然后根据响应的Cache-Control头决定是否缓存结果

三、一些实用提醒

  • Vert.x的连接池是异步非阻塞设计,和Apache HttpClient的同步连接池语义略有不同,但核心的连接数控制逻辑是一致的
  • 生产环境别用本地Map做缓存,建议用Caffeine(本地缓存)或Redis(分布式缓存)来保证可靠性和扩展性
  • 如果需要更复杂的缓存策略(比如缓存验证、过期刷新等),可以参考RFC 7234的规范来完善拦截器逻辑

内容的提问来源于stack exchange,提问作者Philip K. Adetiloye

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:42:53