RestTemplate实践
发布日期:2021-09-06 19:43:26 浏览次数:3 分类:技术文章

本文共 14524 字,大约阅读时间需要 48 分钟。

  在微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端。我们可以使用JDK原生的URLConnection、Apache的Http Client、Netty的异步HTTP Client, Spring的RestTemplate。但是,用起来最方便、最优雅的还是要属Feign了。这里介绍的是RestTemplate。

什么是RestTemplate?

RestTemplate是Spring提供的用于访问Rest服务的客户端,

RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。

调用RestTemplate的默认构造函数,RestTemplate对象在底层通过使用java.net包下的实现创建HTTP 请求,

可以通过使用ClientHttpRequestFactory指定不同的HTTP请求方式。

ClientHttpRequestFactory接口主要提供了两种实现方式

1、一种是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)创建底层的Http请求连接。

2、一种方式是使用HttpComponentsClientHttpRequestFactory方式,底层使用HttpClient访问远程的Http服务,使用HttpClient可以配置连接池和证书等信息。


xml配置的方式

请查看RestTemplate源码了解细节,知其然知其所以然!

RestTemplate默认是使用SimpleClientHttpRequestFactory,内部是调用jdk的HttpConnection,默认超时为-1

基于jdk的spring的RestTemplate

text/plain;charset=UTF-8

使用Httpclient连接池的方式

text/plain;charset=UTF-8

bean初始化+静态工具

线程安全的单例(懒汉模式)

基于jdk的spring的RestTemplate

import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.context.annotation.Lazy;import org.springframework.http.client.SimpleClientHttpRequestFactory;import org.springframework.http.converter.FormHttpMessageConverter;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.http.converter.StringHttpMessageConverter;import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;import org.springframework.stereotype.Component;import org.springframework.web.client.DefaultResponseErrorHandler;import org.springframework.web.client.RestTemplate; import javax.annotation.PostConstruct;import java.nio.charset.Charset;import java.util.ArrayList;import java.util.List; /*** @title:基于jdk的spring的RestTemplate* @author:liuxing* @date:2015-05-18 09:35*/@Component@Lazy(false)public class SimpleRestClient {     private static final Logger LOGGER = LoggerFactory.getLogger(SimpleRestClient.class);     private static RestTemplate restTemplate;     static {        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();        requestFactory.setReadTimeout(5000);        requestFactory.setConnectTimeout(5000);         // 添加转换器        List
> messageConverters = new ArrayList<>(); messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8"))); messageConverters.add(new FormHttpMessageConverter()); messageConverters.add(new MappingJackson2XmlHttpMessageConverter()); messageConverters.add(new MappingJackson2HttpMessageConverter()); restTemplate = new RestTemplate(messageConverters); restTemplate.setRequestFactory(requestFactory); restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); LOGGER.info("SimpleRestClient初始化完成"); } private SimpleRestClient() { } @PostConstruct public static RestTemplate getClient() { return restTemplate; } } 

使用Httpclient连接池的方式

import org.apache.http.Header;import org.apache.http.client.HttpClient;import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;import org.apache.http.impl.client.HttpClientBuilder;import org.apache.http.impl.client.HttpClients;import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;import org.apache.http.message.BasicHeader;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.context.annotation.Lazy;import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;import org.springframework.http.converter.FormHttpMessageConverter;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.http.converter.StringHttpMessageConverter;import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;import org.springframework.stereotype.Component;import org.springframework.web.client.DefaultResponseErrorHandler;import org.springframework.web.client.RestTemplate; import javax.annotation.PostConstruct;import java.nio.charset.Charset;import java.util.ArrayList;import java.util.List;import java.util.concurrent.TimeUnit; /*** @title:使用spring的restTemplate替代httpclient工具* @author:liuxing* @date:2015-05-18 08:48*/@Component@Lazy(false)public class RestClient {     private static final Logger LOGGER = LoggerFactory.getLogger(SimpleRestClient.class);     private static RestTemplate restTemplate;     static {        // 长连接保持30秒        PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);        // 总连接数        pollingConnectionManager.setMaxTotal(1000);        // 同路由的并发数        pollingConnectionManager.setDefaultMaxPerRoute(1000);         HttpClientBuilder httpClientBuilder = HttpClients.custom();        httpClientBuilder.setConnectionManager(pollingConnectionManager);        // 重试次数,默认是3次,没有开启        httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true));        // 保持长连接配置,需要在头添加Keep-Alive        httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()); //        RequestConfig.Builder builder = RequestConfig.custom();//        builder.setConnectionRequestTimeout(200);//        builder.setConnectTimeout(5000);//        builder.setSocketTimeout(5000);////        RequestConfig requestConfig = builder.build();//        httpClientBuilder.setDefaultRequestConfig(requestConfig);         List
headers = new ArrayList<>(); headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36")); headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate")); headers.add(new BasicHeader("Accept-Language", "zh-CN")); headers.add(new BasicHeader("Connection", "Keep-Alive")); httpClientBuilder.setDefaultHeaders(headers); HttpClient httpClient = httpClientBuilder.build(); // httpClient连接配置,底层是配置RequestConfig HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); // 连接超时 clientHttpRequestFactory.setConnectTimeout(5000); // 数据读取超时时间,即SocketTimeout clientHttpRequestFactory.setReadTimeout(5000); // 连接不够用的等待时间,不宜过长,必须设置,比如连接不够用时,时间过长将是灾难性的 clientHttpRequestFactory.setConnectionRequestTimeout(200); // 缓冲请求数据,默认值是true。通过POST或者PUT大量发送数据时,建议将此属性更改为false,以免耗尽内存。 // clientHttpRequestFactory.setBufferRequestBody(false); // 添加内容转换器 List
> messageConverters = new ArrayList<>(); messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8"))); messageConverters.add(new FormHttpMessageConverter()); messageConverters.add(new MappingJackson2XmlHttpMessageConverter()); messageConverters.add(new MappingJackson2HttpMessageConverter()); restTemplate = new RestTemplate(messageConverters); restTemplate.setRequestFactory(clientHttpRequestFactory); restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); LOGGER.info("RestClient初始化完成"); } private RestClient() { } @PostConstruct public static RestTemplate getClient() { return restTemplate; } } 

HttpClientUtils

import com.dooioo.commons.Strings;import com.dooioo.framework.SpringContextHolder;import com.dooioo.ky.cache.HttpClientResultCache;import org.apache.commons.collections.MapUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.http.HttpEntity;import org.springframework.util.LinkedMultiValueMap;import org.springframework.util.MultiValueMap; import java.util.Map; /**** 类功能说明:httpclient工具类,基于httpclient 4.x* Title: HttpClientUtils.java* @author 刘兴* @date 2014-3-7 下午7:48:58* @version V1.0*/public class HttpClientUtils {     private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtils.class);     /**     * post请求     * @param url     * @param formParams     * @return     */    public static String doPost(String url, Map
formParams) { if (MapUtils.isEmpty(formParams)) { return doPost(url); } try { MultiValueMap
requestEntity = new LinkedMultiValueMap<>(); formParams.keySet().stream().forEach(key -> requestEntity.add(key, MapUtils.getString(formParams, key, ""))); return RestClient.getClient().postForObject(url, requestEntity, String.class); } catch (Exception e) { LOGGER.error("POST请求出错:{}", url, e); } return Strings.EMPTY; } /** * post请求 * @param url * @return */ public static String doPost(String url) { try { return RestClient.getClient().postForObject(url, HttpEntity.EMPTY, String.class); } catch (Exception e) { LOGGER.error("POST请求出错:{}", url, e); } return Strings.EMPTY; } /** * get请求 * @param url * @return */ public static String doGet(String url) { try { return RestClient.getClient().getForObject(url, String.class); } catch (Exception e) { LOGGER.error("GET请求出错:{}", url, e); } return Strings.EMPTY; } }  

ErrorHolder

自定义的一个异常结果包装类

使用样例

api里面可以做自动的参数匹配:

如: domainn name/test?empNo={empNo},则下面方法的最后一个参数为数据匹配参数,会自动根据key进行查找,然后替换

API没有声明异常,注意进行异常处理

更多使用语法请查看API文档

RestTemplate处理请求状态码为非200的返回数据

默认的 RestTemplate 有个机制是请求状态码非200 就抛出异常,会中断接下来的操作。如果不想中断对结果数据得解析,可以通过覆盖默认的 ResponseErrorHandler ,见下面的示例,示例中的方法中基本都是空方法,只要对hasError修改下,让他一直返回true,即是不检查状态码及抛异常了。

@Bean("sslRestTemplate")    public RestTemplate getRestTemplate() throws Exception {        RestTemplate sslRestTemplate = new RestTemplate(new HttpsClientRequestFactory());        ResponseErrorHandler responseErrorHandler = new ResponseErrorHandler() {            @Override            public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {                return true;            }            @Override            public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {            }        };        sslRestTemplate.setErrorHandler(responseErrorHandler);        return sslRestTemplate;    }

 

或者,修改resttemplate的源码,把对应的源码文件拷贝到自己的项目中,但不推荐。

 

转载地址:https://blog.csdn.net/weixin_34270865/article/details/85601626 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:继续寻找app开发的技术方案
下一篇:文件上传限制大小 dotnet/C#

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月03日 21时59分54秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章