调用 REST 服务
本教程共 48 篇 · 第 22 篇 · 更新于 2026-08-13 · 约 3 分钟阅读
本节目标:学会用 RestClient 调用远程接口,看懂 WebClient 的响应式写法,知道 RestTemplate 为什么退居二线。
三种客户端怎么选
Spring 家族给了三个 HTTP 客户端,别纠结,先记结论:
| 客户端 | 风格 | 定位 |
|---|---|---|
| RestClient | 命令式,链式 API | 4.x 主线选择 |
| WebClient | 响应式,返回 Mono/Flux | WebFlux 项目用 |
| RestTemplate | 命令式,老 API | 已弃用,只维护存量代码 |
普通 Spring MVC 项目,调远程接口默认选 RestClient。它和 RestTemplate 一样是同步阻塞的,但 API 更现代,好读好写。
RestClient 基础用法
Spring Boot 自动配置了一个 RestClient.Builder,直接注入使用:
package com.example.demo.service;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@Service
public class ProductClient {
private final RestClient restClient;
public ProductClient(RestClient.Builder builder) {
// baseUrl 定根地址,后面只写相对路径
this.restClient = builder.baseUrl("https://api.example.com").build();
}
public String findById(Long id) {
return restClient.get()
.uri("/products/{id}", id)
.retrieve()
.body(String.class);
}
}
链式调用三段式:发起方法(get/post)→ 请求配置(uri/header/body)→ 接收结果(retrieve)。
URI 里的 {id} 是占位符,后面的参数按顺序填充,不用手拼字符串。
调 JSON 接口并转对象
远程接口返回 JSON 时,body() 直接收对象或集合。需要一个配套的模型类:
package com.example.demo.model;
public class Product {
private Long id;
private String name;
private Double price;
// getter / setter 省略
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Double getPrice() { return price; }
public void setPrice(Double price) { this.price = price; }
}
package com.example.demo.service;
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
import com.example.demo.model.Product;
@Service
public class ProductClient {
private final RestClient restClient;
public ProductClient(RestClient.Builder builder) {
this.restClient = builder.baseUrl("https://api.example.com").build();
}
// GET 查询单个
public Product getProduct(Long id) {
return restClient.get()
.uri("/products/{id}", id)
.retrieve()
.body(Product.class);
}
// GET 查询列表
public List<Product> listProducts() {
return restClient.get()
.uri("/products")
.retrieve()
.body(List.class);
}
// POST 提交 JSON
public Product createProduct(Product product) {
return restClient.post()
.uri("/products")
.contentType(MediaType.APPLICATION_JSON)
.body(product)
.retrieve()
.body(Product.class);
}
// DELETE 无响应体
public void deleteProduct(Long id) {
restClient.delete()
.uri("/products/{id}", id)
.retrieve()
.toBodilessEntity();
}
}
Tip
body(List.class)转集合时元素类型是 Object,需要时用ParameterizedTypeReference指定泛型,例如body(new ParameterizedTypeReference<List<Product>>() {})。
出错怎么办
远程返回 4xx/5xx 时,retrieve() 默认抛 RestClientResponseException 的子类。想精细处理,用 onStatus 拦截:
public Product getProduct(Long id) {
return restClient.get()
.uri("/products/{id}", id)
.retrieve()
.onStatus(
status -> status.value() == 404,
(request, response) -> {
throw new NotFoundException("商品不存在");
})
.body(Product.class);
}
状态码符合条件就执行自定义逻辑,把远程错误翻译成本地业务异常。
WebClient:响应式调用
WebFlux 项目里用 WebClient。API 结构和 RestClient 很像,但返回的是响应式类型:
package com.example.demo.service;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import com.example.demo.model.Product;
import reactor.core.publisher.Mono;
@Service
public class ReactiveProductClient {
private final WebClient webClient;
public ReactiveProductClient(WebClient.Builder builder) {
this.webClient = builder.baseUrl("https://api.example.com").build();
}
public Mono<Product> getProduct(Long id) {
return webClient.get()
.uri("/products/{id}", id)
.retrieve()
.bodyToMono(Product.class);
}
}
调用方订阅 Mono 才真正发请求。在同步代码里想立刻拿结果,用 block():
Product product = client.getProduct(1L).block();
NoteWebClient 适合 WebFlux 响应式项目,Spring Boot 会按 classpath 自动选底层连接器(Reactor Netty、Jetty、JDK HttpClient)。MVC 项目用 RestClient 更简单。
RestTemplate:曾经的王者
RestTemplate 是 2009 年就有的老 API,统治了十多年。写法啰嗦,每个请求都要先包 HttpEntity:
// 旧写法:RestTemplate(已弃用,仅对照)
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.getForEntity(
"https://api.example.com/products/{id}", String.class, 1L);
String body = response.getBody();
Spring Framework 官方已将它标记为 deprecated,Spring Boot 4.x 不再提供自动配置的 RestTemplate 实例,只保留 RestTemplateBuilder 方便存量代码构建。
新代码别再用它。理由不只是弃用:API 冗长、错误处理要靠 try-catch 解析响应体、测试也不方便。RestClient 是它的现代替代品,迁移成本很低。
进阶:HTTP Service 接口
Spring 6 起支持声明式 HTTP 客户端:把远程接口定义成 Java 接口,注解描述请求,框架自动生成实现。适合服务之间调用,代码最简洁。
package com.example.demo.client;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.service.annotation.GetExchange;
import org.springframework.web.service.annotation.HttpExchange;
import com.example.demo.model.Product;
@HttpExchange(url = "https://api.example.com")
public interface ProductApi {
@GetExchange("/products/{id}")
Product getProduct(@PathVariable Long id);
}
在主类上注册扫描:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.service.registry.ImportHttpServices;
@SpringBootApplication
@ImportHttpServices(basePackages = "com.example.demo.client")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
之后直接注入 ProductApi 调用,不用写实现类。
本节小结
- MVC 项目调远程接口默认 RestClient,注入自动配置的 Builder。
- WebFlux 项目用 WebClient,响应式 API,需要时 block() 取结果。
- RestTemplate 已弃用,新代码不写,存量代码用 RestTemplateBuilder 维护。
- HTTP Service 接口用注解描述请求,适合服务间调用。