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

Spring Boot中RestTemplate代码迁移至RestClient求助

问题描述

需要将Spring Boot项目中的RestTemplate请求代码迁移为RestClient实现,原RestTemplate代码如下:

private byte[] request(Data data) {
   HttpHeaders headers = new HttpHeaders();
   headers.setContentType(MediaType.APPLICATION_JSON);
   HttpEntity<ResponseData> entity = new HttpEntity<>(data, headers);
   return restTemplate.exchange(url + uri, HttpMethod.POST, entity, byte[].class).getBody();
}

尝试了四种写法均未正常工作,代码如下:

写法一

private byte[] request(Data data) {
    return restClientBuilder.baseUrl(url)
            .build()
            .post()
            .uri(uri)
            .contentType(MediaType.APPLICATION_JSON)
            .body(data)
            .retrieve()
            .onStatus(HttpStatusCode::isError, new ApiErrorHandler())
            .toEntity(byte[].class).getBody();
}

写法二

private byte[] request(Data data) {
    return restClientBuilder.baseUrl(url)
            .build()
            .post()
            .uri(uri)
            .contentType(MediaType.APPLICATION_JSON)
            .body(data)
            .retrieve()
            .onStatus(HttpStatusCode::isError, new ApiErrorHandler())
            .body(byte[].class);
}

写法三

private byte[] request(Data data) {
    return restClientBuilder.baseUrl(url)
            .build()
            .post()
            .uri(uri)
            .contentType(MediaType.APPLICATION_JSON)
            .body(data)
            .exchange((request, res) -> res.getBody().readAllBytes());
}

写法四

private byte[] requestD(Data data) {
    return restClientBuilder.baseUrl(url)
            .build()
            .post()
            .uri(uri)
            .contentType(MediaType.APPLICATION_JSON)
            .body(data)
            .retrieve()
            .onStatus(HttpStatusCode::isError, new ApiErrorHandler())
            .toEntity(new ParameterizedTypeReference<byte[]>() {
            }).getBody();
}

正确实现方案

以下是与原RestTemplate代码完全等效的RestClient实现,同时解决了之前写法的潜在问题:

private byte[] request(Data data) {
    // 建议提前初始化RestClient实例并注入Spring容器,避免每次请求重复build
    RestClient restClient = restClientBuilder.baseUrl(url).build();
    
    return restClient.post()
            .uri(uri)
            .contentType(MediaType.APPLICATION_JSON)
            .body(data)
            .retrieve()
            .onStatus(HttpStatusCode::isError, (request, response) -> {
                // 确保ApiErrorHandler正确处理错误并抛出异常,中断正常响应流程
                new ApiErrorHandler().handle(request, response);
            })
            .body(new ParameterizedTypeReference<byte[]>() {});
}

常见问题排查

  1. ApiErrorHandler实现问题:
    前三种写法逻辑本身无错误,大概率是ApiErrorHandler未正确实现ResponseErrorHandler接口,或者handle方法没有抛出异常。错误处理逻辑必须抛出异常,才能中断RestClient的正常响应解析流程。
  2. 写法三的资源泄漏:
    exchange中直接调用res.getBody().readAllBytes()需要手动关闭输入流,否则会导致连接池资源泄漏。优先使用retrieve()方式,RestClient会自动管理资源。
  3. 重复构建RestClient:
    每次请求调用build()会重复创建客户端实例,影响性能。建议在配置类中初始化RestClient并注入容器,直接使用注入的实例即可。

简化版(无自定义错误处理)

如果不需要自定义错误处理,可以省略onStatus,RestClient会默认抛出对应状态码的异常:

private byte[] request(Data data) {
    return restClient.post()
            .uri(uri)
            .contentType(MediaType.APPLICATION_JSON)
            .body(data)
            .retrieve()
            .body(byte[].class);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 13:47:37