Spring RestTemplate 发 HTTP 请求:常用姿势速查

Spring 里发 HTTP 请求最常见还是 RestTemplate。虽然官方已经推 WebClient,但存量项目里 RestTemplate 到处都是——写起来简单、同步阻塞、跟传统 Servlet 模型贴合。

注册 Bean

@Configuration
public class RestConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

注入用:

@Autowired
private RestTemplate restTemplate;

或者构造器注入(推荐):

private final RestTemplate rt;
public UserService(RestTemplate rt) { this.rt = rt; }

GET

最简单

String json = restTemplate.getForObject(
    "https://api.example.com/users/1",
    String.class);

带 URL 参数(占位符按顺序填):

String url = "https://api.example.com/users/{id}?type={type}";
String json = restTemplate.getForObject(url, String.class, 1, "vip");

返回对象

@Data
public class User {
    private Integer id;
    private String name;
}

User u = restTemplate.getForObject(
    "https://api.example.com/users/1",
    User.class);

Jackson 会自动反序列化——User 里字段名和 JSON 对得上就行。

POST

发 JSON

Map<String, Object> body = new HashMap<>();
body.put("username", "admin");
body.put("password", "12345");

String result = restTemplate.postForObject(
    "https://api.example.com/login",
    body,
    String.class);

RestTemplate 会把 Map 序列化成 JSON 并设 Content-Type: application/json(前提是有 Jackson)。

表单

MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
form.add("username", "admin");
form.add("password", "12345");

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

HttpEntity<MultiValueMap<String, String>> req = new HttpEntity<>(form, headers);
String result = restTemplate.postForObject(url, req, String.class);

自定义 Header

带 Token 的接口:

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + token);

Map<String, Object> body = new HashMap<>();
body.put("name", "test");

HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);

ResponseEntity<String> resp = restTemplate.exchange(
    "https://api.example.com/create",
    HttpMethod.POST,
    entity,
    String.class);

if (resp.getStatusCode().is2xxSuccessful()) {
    System.out.println(resp.getBody());
}

exchange 是最灵活的方法——可以自由选择 HTTP method、传 headers、拿完整的 ResponseEntity

超时配置(生产必配)

默认没有超时。远端 hang 住就一直等:

@Bean
public RestTemplate restTemplate() {
    SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
    factory.setConnectTimeout(5_000);   // 连接超时
    factory.setReadTimeout(10_000);     // 读超时
    return new RestTemplate(factory);
}

更强大的选择:Apache HttpClient 5:

@Bean
public RestTemplate restTemplate() {
    RequestConfig config = RequestConfig.custom()
        .setConnectTimeout(Timeout.ofSeconds(5))
        .setResponseTimeout(Timeout.ofSeconds(10))
        .build();

    CloseableHttpClient http = HttpClients.custom()
        .setDefaultRequestConfig(config)
        .setMaxConnTotal(100)
        .setMaxConnPerRoute(20)
        .build();

    HttpComponentsClientHttpRequestFactory factory =
        new HttpComponentsClientHttpRequestFactory(http);
    return new RestTemplate(factory);
}

带连接池、更好的性能、支持重试。

上传文件

FileSystemResource file = new FileSystemResource("/path/to/a.zip");

MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", file);
body.add("desc", "备份");

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);

HttpEntity<MultiValueMap<String, Object>> req = new HttpEntity<>(body, headers);

String result = restTemplate.postForObject(
    "https://api.example.com/upload",
    req, String.class);

忽略 SSL

自签证书内网服务:

SSLContext ssl = SSLContexts.custom()
    .loadTrustMaterial((chain, authType) -> true)
    .build();

CloseableHttpClient http = HttpClients.custom()
    .setConnectionManager(
        PoolingHttpClientConnectionManagerBuilder.create()
            .setSSLSocketFactory(
                SSLConnectionSocketFactoryBuilder.create()
                    .setSslContext(ssl)
                    .setHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                    .build())
            .build())
    .build();

生产上少这么干,会漏中间人。

Spring Boot 3 之后怎么办

Spring Framework 6 起 RestTemplate 进入维护模式——不再加新功能,但不会立刻删。新项目推荐:

  • RestClient(Spring 6.1+)— 同步、fluent API,最平滑的替代
  • WebClient — 响应式(reactive),跟 Reactor 生态整合

RestClient 示例:

RestClient client = RestClient.create();

User u = client.get()
    .uri("https://api.example.com/users/{id}", 1)
    .retrieve()
    .body(User.class);

RestTemplate 好看得多。老项目不用急着换,新代码优先用 RestClient

一句话总结

RestTemplate:GET 用 getForObject、POST 用 postForObjectexchange、复杂场景走 exchangeResponseEntity生产必配超时和连接池。新项目改用 RestClient