找回密码
 立即注册
首页 业界区 安全 [HTTP/Spring] RestTemplate : Spring的HTTP网络请求框 ...

[HTTP/Spring] RestTemplate : Spring的HTTP网络请求框架

即息极 2025-9-23 18:57:31
1 概述: RestTemplate

RestTemplate 的产生背景、存在意义


  • java应用开发中,使用http连接,访问第三方HTTP接口,通常使用的HTTP连接请求工具为HttpClient和OKHttp。
  • 这两种HTTP连接请求工具,使用起来比较复杂,新手容易出问题。如果使用spring框架,可以使用restTemplate来进行http连接请求。
  • restTemplate默认的连接方式是java中的HttpConnection,可以使用ClientHttpRequestFactory指定不同的HTTP连接方式。


  • [Java SE/JDK/网络] 核心源码精讲:java.net.HttpURLConnection - 博客园/千千寰宇
  • [Java/网络/HTTP(S)] 基于Http(s)URLConnection的网络请求工具(HttpRequestUtils) - 博客园/千千寰宇


  • 相比其他http网络请求框架,RestTemplate最大的价值在于:

  • 与spring无缝衔接的原生集成优势
  • 封装/屏蔽了底层的连接框架,如 OKhttp、httpclient等
  • 解决了:封装java dto 与http响应的转换逻辑等问题,使得java开发工程师无需关注底层的http连接问题,使其高度聚焦于业务的开发。
RestTemplate 介绍


  • org.springframework.web.client.RestTemplate 是 Spring Resources 中一个访问第三方 RESTful API 接口的网络请求框架,用于执行HTTP请求。
  • 其暴露了一系列的模板方法API,便于操作底层的HTTP客户端库,如JDK的HttpURLConnection、Apache HttpComponents等。
  • RestTemplate 是用来消费 REST 服务的,所以 RestTemplate 的主要方法都与 REST 的 Http协议的一些方法紧密相连
例如 HEAD、GET、POST、PUT、DELETE 和 OPTIONS 等方法。
这些方法在 RestTemplate 类对应的方法为 headForHeaders()、getForObject()、postForObject()、put() 和 delete() 等。


  • RestTemplate通常作为【共享组件】使用,其配置不支持【并发修改】,因此通常在【启动时】准备好配置。
如果需要,可以在启动时创建多个配置不同的RestTemplate实例。
这些实例可以使用相同的底层ClientHttpRequestFactory,如果它们需要共享HTTP客户端资源。
2 RestTemplate 使用指南

Maven 依赖
  1. <dependency>
  2.     <groupId>org.springframework</groupId>
  3.     spring-web</artifactId>
  4.     <version>5.2.2.RELEASE</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>org.apache.httpcomponents</groupId>
  8.     httpclient</artifactId>
  9.     <version>4.5.7</version>
  10. </dependency>
复制代码
RestTemplate的初始配置

基本配置
  1. @Configuration
  2. public class RestTemplateConfig {
  3.   @Bean
  4.   public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
  5.     return new RestTemplate(factory);
  6.   }
  7.   @Bean
  8.   public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
  9.     SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
  10.     factory.setReadTimeout(150000); // ms
  11.     factory.setConnectTimeout(150000); // ms
  12.     return factory;
  13.   }
  14. }
复制代码
进阶配置

除了基础配置,还可以进行更高级的配置,例如设置连接池、自定义HttpClient等。
  1. @Configuration
  2. public class RestTemplateConfig {
  3.     @Bean
  4.     public HttpClientConnectionManager poolingHttpClientConnectionManager() {
  5.         PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
  6.         poolingHttpClientConnectionManager.setMaxTotal(500); // 最大连接数
  7.         poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); // 同路由并发数
  8.         return poolingHttpClientConnectionManager;
  9.     }
  10.     @Bean
  11.     public HttpClient httpClient(HttpClientConnectionManager poolingHttpClientConnectionManager) {
  12.         HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
  13.         httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
  14.         return httpClientBuilder.build();
  15.     }
  16.     @Bean
  17.     public ClientHttpRequestFactory clientHttpRequestFactory(HttpClient httpClient) {
  18.         HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
  19.         clientHttpRequestFactory.setHttpClient(httpClient);
  20.         clientHttpRequestFactory.setConnectTimeout(5 * 1000); // 连接超时时间
  21.         clientHttpRequestFactory.setReadTimeout(10 * 1000); // 数据读取超时时间
  22.         clientHttpRequestFactory.setConnectionRequestTimeout(10 * 1000); // 连接池获取请求连接的超时时间
  23.         return clientHttpRequestFactory;
  24.     }
  25.     @Bean
  26.     public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
  27.         RestTemplate restTemplate = new RestTemplate();
  28.         restTemplate.setRequestFactory(clientHttpRequestFactory);
  29.         return restTemplate;
  30.     }
  31. }
复制代码
最佳实践: RestTemplateConfig
  1. import org.apache.http.client.HttpClient;
  2. import org.apache.http.conn.HttpClientConnectionManager;
  3. import org.apache.http.impl.client.HttpClientBuilder;
  4. import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.http.client.ClientHttpRequestFactory;
  8. import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
  9. import org.springframework.web.client.RestTemplate;
  10. @Configuration
  11. public class RestTemplateConfig {
  12.    
  13.     /**
  14.      * http连接管理器
  15.      * @return
  16.      */
  17.     @Bean
  18.     public HttpClientConnectionManager poolingHttpClientConnectionManager() {
  19.         /*// 注册http和https请求
  20.         Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
  21.                 .register("http", PlainConnectionSocketFactory.getSocketFactory())
  22.                 .register("https", SSLConnectionSocketFactory.getSocketFactory())
  23.                 .build();
  24.         PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);*/
  25.         
  26.         PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
  27.         // 最大连接数
  28.         poolingHttpClientConnectionManager.setMaxTotal(500);
  29.         // 同路由并发数(每个主机的并发)
  30.         poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);
  31.         return poolingHttpClientConnectionManager;
  32.     }
  33.    
  34.     /**
  35.      * HttpClient
  36.      * @param poolingHttpClientConnectionManager
  37.      * @return
  38.      */
  39.     @Bean
  40.     public HttpClient httpClient(HttpClientConnectionManager poolingHttpClientConnectionManager) {
  41.         HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
  42.         // 设置http连接管理器
  43.         httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
  44.         
  45.         /*// 设置重试次数
  46.         httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true));*/
  47.         
  48.         // 设置默认请求头
  49.         /*List<Header> headers = new ArrayList<>();
  50.         headers.add(new BasicHeader("Connection", "Keep-Alive"));
  51.         httpClientBuilder.setDefaultHeaders(headers);*/
  52.         
  53.         return httpClientBuilder.build();
  54.     }
  55.    
  56.     /**
  57.      * 请求连接池配置
  58.      * @param httpClient
  59.      * @return
  60.      */
  61.     @Bean
  62.     public ClientHttpRequestFactory clientHttpRequestFactory(HttpClient httpClient) {
  63.         HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
  64.         // httpClient创建器
  65.         clientHttpRequestFactory.setHttpClient(httpClient);
  66.         // 连接超时时间/毫秒(连接上服务器(握手成功)的时间,超出抛出connect timeout)
  67.         clientHttpRequestFactory.setConnectTimeout(5 * 1000);
  68.         // 数据读取超时时间(socketTimeout)/毫秒(务器返回数据(response)的时间,超过抛出read timeout)
  69.         clientHttpRequestFactory.setReadTimeout(10 * 1000);
  70.         // 连接池获取请求连接的超时时间,不宜过长,必须设置/毫秒(超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool)
  71.         clientHttpRequestFactory.setConnectionRequestTimeout(10 * 1000);
  72.         return clientHttpRequestFactory;
  73.     }
  74.    
  75.     /**
  76.      * rest模板
  77.      * @return
  78.      */
  79.     @Bean
  80.     public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
  81.         // boot中可使用RestTemplateBuilder.build创建
  82.         RestTemplate restTemplate = new RestTemplate();
  83.         // 配置请求工厂
  84.         restTemplate.setRequestFactory(clientHttpRequestFactory);
  85.         return restTemplate;
  86.     }
  87.    
  88. }
复制代码
RestTemplate的日常使用 := 发起HTTP请求


  • RestTemplate的使用非常灵活,可以支持各种HTTP方法的请求,如GET、POST、PUT、DELETE等。
以下是一些使用RestTemplate的示例:
  1. TempUserDto result = restTemplate.getForObject("http://localhost:8080/cs-admin/rest/getUser?userName=张三&age=18", TempUserDto.class);
复制代码
GET请求


  • case 1 基于普通参数,映射请求参数到 Get URL Params
  1. String url = "http://localhost:8080/api/users/{id}";
  2. User user = restTemplate.getForObject(url, User.class, 1);
复制代码

  • case 2 基于Map对象,映射请求参数到 Get URL Params
  1. Map<String, Object> paramMap = new HashMap<>();
  2. paramMap.put("userName", "张三");
  3. paramMap.put("age", 18);
  4. TempUser result = restTemplate.getForObject("http://localhost:8080/cs-admin/rest/getUser?userName={userName}&age={age}", TempUser.class, paramMap);
复制代码
POST请求

普通访问接口
  1. String url = "http://localhost:8080/api/users";
  2. User newUser = new User("张三", 30);
  3. URI location = restTemplate.postForLocation(url, newUser);
复制代码
  1. TempUser param = new TempUser();
  2. param.setUserName("张三");
  3. param.setAge(18);
  4. TempUser result = restTemplate.postForObject("http://localhost:8080/cs-admin/rest/getPostUser", param, TempUser.class);
复制代码
带HEAD访问接口
  1. // 请求头信息
  2. HttpHeaders headers = new HttpHeaders();
  3. headers.setContentType(MediaType.valueOf("application/json;charset=UTF-8"));
  4. //headers.add("headParam1", "headParamValue");
  5. // 请求体内容
  6. TempUser param = new TempUser();
  7. param.setUserName("张三");
  8. param.setAge(18);
  9. // 组装请求信息
  10. HttpEntity<TempUser> httpEntity=new HttpEntity<>(param,headers);
  11. TempUser result = restTemplate.postForObject("http://localhost:8080/cs-admin/rest/getPostUser", httpEntity, TempUser.class);
复制代码
无请求体的访问

仅method为post,传参方式仍然为get的param方式
  1. Map<String, Object> paramMap = new HashMap<>();
  2. paramMap.put("userName", "张三");
  3. paramMap.put("age", 18);
  4. TempUser result = restTemplate.postForObject("http://localhost:8080/cs-admin/rest/getPostUserNoBody?userName={userName}&age={age}", null, TempUser.class, paramMap);
  5. System.out.println(result);
复制代码
发送可携带文件的请求
  1. public static void main(String[] args) {
  2.     final RestTemplate restTemplate = new RestTemplate();
  3.     MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
  4.     map.add("fileUuid","oldDocumentTrans.getFileUuid()");
  5.     map.add("sourceLanguageAbbreviation","en");
  6.     map.add("targetLanguageAbbreviation","zh");
  7.     HttpHeaders headers = new HttpHeaders();
  8.     HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);
  9.     final ResponseEntity<String> stringResponseEntity = restTemplate.postForEntity("http://localhost:8055/documentTrans/updateLanguages",
  10.         map,
  11.         String.class
  12.     );
  13.     System.out.println(stringResponseEntity);
  14. }
复制代码
上传文件


  • 后台接口代码
  1. @RequestMapping("uploadFile")
  2. public TempUser uploadFile(HttpServletRequest request, TempUser form) {
  3.    MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
  4.    
  5.    //获取文件信息
  6.    MultipartFile multipartFile = multipartHttpServletRequest.getFile("file");
  7.    TempUser tempUser = new TempUser();
  8.    if (multipartFile != null) {
  9.        tempUser.setUserName(form.getUserName()+" "+multipartFile.getOriginalFilename());
  10.    }
  11.    if(form!=null){
  12.        tempUser.setAge(form.getAge());
  13.    }
  14.    return tempUser;
  15. }
复制代码

  • RestTemplate 访问(上传文件)
  1. // 文件
  2. FileSystemResource file = new FileSystemResource("D:\\Java 权威指南(中文版).pdf");
  3. // 设置请求内容
  4. MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
  5. param.add("file", file);
  6. // 其他参数
  7. param.add("userName", "张三");
  8. param.add("age", 18);
  9. // 组装请求信息
  10. HttpEntity<MultiValueMap<String, Object>> httpEntity=new HttpEntity<>(param);
  11. // 发送请求
  12. TempUser result = restTemplate.postForObject("http://localhost:8080/cs-admin/rest/uploadFile", httpEntity, TempUser.class);
复制代码
PUT请求
  1. String url = "http://localhost:8080/api/users/{id}";
  2. User updatedUser = new User("李四", 40);
  3. restTemplate.put(url, updatedUser, 1);
复制代码
DELETE请求
  1. String url = "http://localhost:8080/api/users/{id}";
  2. restTemplate.delete(url, 1);
复制代码
获取HTTP响应状态
  1. ResponseEntity<TempUser> responseEntity = restTemplate.getForEntity("http://localhost:8080/cs-admin/rest/getUser?userName=张三&age=18", TempUser.class);
  2. // 获取状态对象
  3. HttpStatus httpStatus = responseEntity.getStatusCode();
  4. // 获取状态码
  5. int statusCodeValue = responseEntity.getStatusCodeValue();
  6. // 获取headers
  7. HttpHeaders httpHeaders = responseEntity.getHeaders();
  8. // 获取body
  9. TempUser result = responseEntity.getBody();
复制代码
通过这些示例可以看出,RestTemplate提供了一种简洁的方式来消费RESTful服务。
它封装了HTTP连接的复杂性,使得开发者可以更专注于业务逻辑的实现。
3 Spring WebClient : Spring RestTemplate 的继承者、下一代(支持非阻塞式/支持响应式)

Spring WebClient 简介

Spring WebClient : Spring RestTemplate 的下一代/继承者


  • Spring WebClient 是 Spring Framework 5 引入的一个非阻塞响应式的 HTTP 客户端,用于与 RESTful 服务进行交互。
它是 RestTemplate 的现代替代品,支持同步异步操作,并且能够很好地与 Spring WebFlux 集成。


  • Spring WebClient


  • https://docs.spring.io/spring-framework/reference/web/webflux-webclient.html
Maven 依赖
  1. <dependency>
  2.   <groupId>org.springframework.boot</groupId>
  3.   spring-boot-starter-webflux</artifactId>
  4. </dependency>
复制代码
使用指南

配置


  • 初始配置
  1. WebClient client = WebClient.builder()
  2. .baseUrl("http://localhost:8080")
  3. .defaultCookie("cookieKey", "cookieValue")
  4. .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
  5. .build();
复制代码
使用


  • 请求


  • GET Request
  1. Mono<Employee> employeeMono = client.get()
  2. .uri("/employees/{id}", 123)
  3. .retrieve()
  4. .bodyToMono(Employee.class);
复制代码


  • POST Request
  1. Mono<Employee> employeeMono = client.post()
  2. .uri("/employees")
  3. .body(Mono.just(new Employee("John", "Doe")), Employee.class)
  4. .retrieve()
  5. .bodyToMono(Employee.class);
复制代码


  • PUT Request
  1. Mono<Employee> employeeMono = client.put()
  2. .uri("/employees/{id}", 123)
  3. .body(Mono.just(new Employee("John", "Doe")), Employee.class)
  4. .retrieve()
  5. .bodyToMono(Employee.class);
复制代码


  • DELETE Request
  1. Mono<Void> response = client.delete()
  2. .uri("/employees/{id}", 123)
  3. .retrieve()
  4. .bodyToMono(Void.class);
复制代码


  • 使用 retrieve()
retrieve()方法是一个简化的API,适用于希望发送HTTP请求、接收响应并以响应式方式处理这些请求和响应的常见用例。
  1. Mono<Employee> employeeMono = client.get()
  2. .uri("/employees/{id}", 123)
  3. .retrieve()
  4. .bodyToMono(Employee.class);
复制代码


  • 使用 exchange()
exchange() 方法允许您显式地处理请求和响应。
它返回一个 ClientResponse,其中包含所有响应元素,如状态、标头和响应正文。
  1. Mono<ClientResponse> responseMono = client.get()
  2. .uri("/employees/{id}", 123)
  3. .exchange();
  4. responseMono.subscribe(clientResponse -> {
  5.   HttpStatus statusCode = clientResponse.statusCode();
  6.   HttpHeaders headers = clientResponse.headers();
  7.   Mono<Employee> employeeMono = clientResponse.bodyToMono(Employee.class);
  8.   // Handle the response, including error handling based on status code
  9. });
复制代码
Y 推荐文献


  • ResTemplate - Spring


  • https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html


  • Spring WebClient


  • https://docs.spring.io/spring-framework/reference/web/webflux-webclient.html


  • [Java SE/JDK/网络] 核心源码精讲:java.net.HttpURLConnection - 博客园/千千寰宇


  • [Java/网络/HTTP(S)] 基于Http(s)URLConnection的网络请求工具(HttpRequestUtils) - 博客园/千千寰宇


  • [计算机网络/HTTP/网络请求] Okhttp: 网络请求框架 - 博客园/千千寰宇
  • [高可用/负载均衡] Ribbon : 开源的客户端式负载均衡框架 - 博客园/千千寰宇
Spring Cloud 框架中,Ribbon (负载均衡器) 是如何与 Spring 的 RestTemplate 集成的?
用 @LoadBalanced 标记后,调用 RestTemplate 的 REST 方法就会通过【负载均衡】的方式通过一定的负载策略【路由】到某个【服务实例】上。
X 参考文献


  • The Guide to RestTemplate - baeldung.com
  • Springboot之restTemplate配置及使用 - CSDN
    本文作者:        千千寰宇   
    本文链接:         https://www.cnblogs.com/johnnyzen   
    关于博文:评论和私信会在第一时间回复,或直接私信我。   
    版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA     许可协议。转载请注明出处!
    日常交流:大数据与软件开发-QQ交流群: 774386015        【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!   

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册