RestTemplate
RestTemplate 是 Spring 提供的同步 HTTP 客户端,封装了 HTTP 请求的发送与响应解析。Spring Boot 3.x 中仍可使用,但官方已将其标记为维护模式,新项目建议使用 WebClient(支持响应式)或 Spring Boot 3.2+ 引入的 RestClient(同步,更简洁)。
快速开始
Spring Boot 不自动注入 RestTemplate,需手动声明 Bean:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.connectTimeout(Duration.ofSeconds(3))
.readTimeout(Duration.ofSeconds(10))
.build();
}
}基本请求
GET
@Service
public class WeatherService {
private final RestTemplate restTemplate;
private static final String BASE_URL = "https://api.example.com";
// 返回字符串
public String getRaw(String city) {
return restTemplate.getForObject(BASE_URL + "/weather?city={city}",
String.class, city);
}
// 返回对象(自动 JSON 反序列化)
public WeatherResponse getWeather(String city) {
return restTemplate.getForObject(BASE_URL + "/weather?city={city}",
WeatherResponse.class, city);
}
// 获取完整响应(含状态码和 Header)
public ResponseEntity<WeatherResponse> getWithMeta(String city) {
return restTemplate.getForEntity(BASE_URL + "/weather?city={city}",
WeatherResponse.class, city);
}
// 泛型:List<User> 需用 ParameterizedTypeReference
public List<User> listUsers() {
ResponseEntity<List<User>> response = restTemplate.exchange(
BASE_URL + "/users",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<User>>() {}
);
return response.getBody();
}
}POST
// 发送 JSON 请求体,返回对象
public OrderResponse createOrder(CreateOrderRequest request) {
return restTemplate.postForObject(BASE_URL + "/orders",
request, OrderResponse.class);
}
// 获取响应头中的 Location(创建资源后常见)
public URI createAndGetLocation(CreateOrderRequest request) {
ResponseEntity<Void> response = restTemplate.postForLocation(
BASE_URL + "/orders", request);
return response.getHeaders().getLocation();
}PUT / DELETE
// PUT 无返回值
public void updateUser(Long id, User user) {
restTemplate.put(BASE_URL + "/users/{id}", user, id);
}
// DELETE
public void deleteUser(Long id) {
restTemplate.delete(BASE_URL + "/users/{id}", id);
}exchange — 通用方法
exchange 可完整控制请求方法、Header、请求体和响应类型:
public UserResponse getUserWithAuth(Long id, String token) {
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(token);
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
HttpEntity<Void> entity = new HttpEntity<>(headers);
ResponseEntity<UserResponse> response = restTemplate.exchange(
BASE_URL + "/users/{id}",
HttpMethod.GET,
entity,
UserResponse.class,
id
);
if (!response.getStatusCode().is2xxSuccessful()) {
throw new ServiceException("获取用户失败: " + response.getStatusCode());
}
return response.getBody();
}请求头与参数构建
// URI 模板变量(Map 形式)
Map<String, Object> params = Map.of("city", "Beijing", "lang", "zh");
String url = BASE_URL + "/weather?city={city}&lang={lang}";
WeatherResponse resp = restTemplate.getForObject(url, WeatherResponse.class, params);
// 使用 UriComponentsBuilder 构建复杂 URL
URI uri = UriComponentsBuilder.fromHttpUrl(BASE_URL + "/search")
.queryParam("keyword", "spring boot")
.queryParam("page", 1)
.queryParam("size", 20)
.build()
.toUri();
String result = restTemplate.getForObject(uri, String.class);拦截器
统一处理 Header 注入(如 Token)、日志记录、签名等:
@Component
public class AuthInterceptor implements ClientHttpRequestInterceptor {
private final TokenProvider tokenProvider;
@Override
public ClientHttpResponse intercept(
HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {
request.getHeaders().setBearerAuth(tokenProvider.getToken());
ClientHttpResponse response = execution.execute(request, body);
// 记录请求日志
log.info("[HTTP] {} {} → {}", request.getMethod(),
request.getURI(), response.getStatusCode());
return response;
}
}
// 注册拦截器
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder,
AuthInterceptor authInterceptor) {
return builder
.additionalInterceptors(authInterceptor)
.connectTimeout(Duration.ofSeconds(3))
.readTimeout(Duration.ofSeconds(10))
.build();
}连接池(Apache HttpClient)
默认使用 JDK HttpURLConnection(无连接池),高并发场景建议切换到 Apache HttpClient:
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>@Bean
public RestTemplate restTemplate() {
PoolingHttpClientConnectionManager manager =
new PoolingHttpClientConnectionManager();
manager.setMaxTotal(200); // 总连接数
manager.setDefaultMaxPerRoute(50); // 每个路由最大连接数
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(manager)
.evictIdleConnections(TimeValue.ofSeconds(30))
.build();
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory(httpClient);
factory.setConnectTimeout(3000);
factory.setReadTimeout(10000);
return new RestTemplate(factory);
}错误处理
默认 DefaultResponseErrorHandler 在 4xx/5xx 时抛出 HttpClientErrorException / HttpServerErrorException,可自定义:
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.errorHandler(new ResponseErrorHandler() {
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return response.getStatusCode().isError();
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
HttpStatusCode status = response.getStatusCode();
String body = StreamUtils.copyToString(
response.getBody(), StandardCharsets.UTF_8);
if (status.is4xxClientError()) {
throw new ClientException(status.value(), body);
}
if (status.is5xxServerError()) {
throw new ServerException(status.value(), body);
}
}
})
.build();
}重试
配合 Spring Retry 实现自动重试(适合幂等 GET 请求):
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>@EnableRetry
@Configuration
public class RetryConfig {}
@Service
public class RemoteService {
@Retryable(
retryFor = { ResourceAccessException.class, ServerException.class },
maxAttempts = 3,
backoff = @Backoff(delay = 500, multiplier = 2)
)
public String fetchData(String id) {
return restTemplate.getForObject(BASE_URL + "/data/{id}",
String.class, id);
}
@Recover
public String recover(Exception e, String id) {
log.error("重试耗尽,id={}", id, e);
return null;
}
}RestClient(Spring Boot 3.2+ 推荐)
RestClient 是 Spring 6.1 引入的同步替代品,API 更简洁,与 RestTemplate 底层共享连接工厂:
RestClient client = RestClient.builder()
.baseUrl(BASE_URL)
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token)
.build();
// GET
WeatherResponse weather = client.get()
.uri("/weather?city={city}", "Beijing")
.retrieve()
.body(WeatherResponse.class);
// POST
OrderResponse order = client.post()
.uri("/orders")
.contentType(MediaType.APPLICATION_JSON)
.body(request)
.retrieve()
.body(OrderResponse.class);RestTemplate vs WebClient vs RestClient
| 特性 | RestTemplate | RestClient | WebClient |
|---|---|---|---|
| 编程模型 | 同步阻塞 | 同步阻塞 | 异步/响应式 |
| Spring Boot 版本 | 所有版本 | 3.2+ | 2.x+ (WebFlux) |
| API 风格 | 方法重载多 | 流式链式 | 流式链式 |
| 状态 | 维护模式 | 推荐 | 推荐(响应式) |