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

Spring Boot中如何处理大量HTTP GET请求以降低整体接口调用耗时

批量HTTP请求耗时优化方案

核心优化思路:利用WebClient异步特性并发请求

你当前使用的Spring WebClient是反应式非阻塞客户端,天生支持异步并发请求,不需要额外引入同步线程池,仅调整批量请求组装逻辑即可大幅压缩总耗时。

具体实现步骤

  • 首先调整HttpClient连接池配置,默认连接池最大连接数仅为256,可根据目标API限流规则调整到合适值,同时优化超时时间:
HttpClient client = HttpClient.create()
        // 调整连接池最大连接数,可根据API限流规则灵活调整
        .resolver(spec -> spec.queryTimeout(Duration.ofSeconds(10)))
        .responseTimeout(Duration.ofSeconds(10)) // 单请求平均耗时6秒,设置10秒超时足够,无需保留60秒配置
        .followRedirect(true);
  • 批量转换1676条GeoInfo参数为请求任务,通过Flux控制并发度执行,避免触发API限流:
// 1. 拿到全量请求参数列表
List<GeoInfo> geoList = gs.getGeoXY();
// 2. 批量构造请求,设置并发度为200(可根据API限流阈值灵活调整)
Flux.fromIterable(geoList)
    .flatMap(geo -> {
        // 每个坐标对应生成一个独立请求
        return wc.get()
                .uri(uriBuilder -> uriBuilder.path("/getVilageFcst")
                        .queryParam("serviceKey", serviceKey)
                        .queryParam("numOfRows", numOfRows)
                        .queryParam("pageNo", pageNo)
                        .queryParam("dataType", dataType)
                        .queryParam("base_date", base_date)
                        .queryParam("base_time", base_time)
                        .queryParam("nx", geo.getNx())
                        .queryParam("ny", geo.getNy())
                        .build())
                .retrieve()
                .onStatus(HttpStatus::is4xxClientError,
                        error -> Mono.error(new RuntimeException("API请求错误:" + error.statusCode())))
                .onStatus(HttpStatus::is5xxServerError,
                        error -> Mono.error(new RuntimeException("服务端错误:" + error.statusCode())))
                .bodyToMono(SweatherRootRes.class)
                // 单请求出错不中断整体任务,打印日志后继续执行后续请求
                .doOnError(e -> logger.error("请求坐标nx:{}, ny:{}失败,原因:{}", geo.getNx(), geo.getNy(), e.getMessage()))
                .onErrorResume(e -> Mono.empty());
    }, 200) // 此处200为并发请求数,可根据实际情况调整
    .doOnNext(res -> {
        // 单请求成功后的处理逻辑
        if(res.getResponse().getBody()!= null) {
            // 注意不要使用单例注入的Temperature对象,每个请求独立创建对象避免数据覆盖
            Temperature temp = new Temperature();
            Items items = res.getResponse().getBody().getItems();
            int count = 0;
            for(Item item : items.getItem()) {
                if(count >= 2 ) 
                    break;
                if(item.getCategory().equals("TMX")) {
                    temp.setBestMax(item.getFcstValue());
                    temp.setNx(item.getNx());
                    temp.setNy(item.getNy());
                    temp.setDate(item.getBaseDate());
                    count++;
                }
                if(item.getCategory().equals("TMN")){
                    temp.setBestMin(item.getFcstValue());
                    count++;
                }
            }
            logger.info("坐标nx:{}, ny:{} 温度数据:{}", temp.getNx(), temp.getNy(), temp.toString());
            // 此处可补充持久化逻辑,将温度数据写入数据库
        }
    })
    // 阻塞等待所有请求执行完成
    .blockLast();

耗时预估

如果并发度设置为200,1676次请求仅需要9轮即可跑完,总耗时约为9*6=54秒,相比原有3小时的执行时长提升非常明显。

注意事项

  • 并发度不要超过目标API的限流阈值,不确定限流规则时可先调低到50测试,避免被API提供商封禁IP
  • 原有代码中注入的Temperature、SweatherRootRes是单例对象,批量请求时必须每个请求独立创建新对象,否则会出现数据覆盖问题
  • 可补充请求重试机制,对超时、异常的请求重试1-2次,提升请求成功率

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 22:27:03