RestTemplate 使用总结
场景:
认证服务器需要有个 http client 把前端发来的请求转发到 backend service, 然后把 backend service 的结果再返回给前端,服务器本身只做认证功能。
遇到的问题:
-
长连接以保证高性能。RestTemplate 本身也是一个 wrapper 其底层默认是 SimpleClientHttpRequestFactory ,如果要保证长连接, HttpComponentsClientHttpRequestFactory 是个更好的选择,它不仅可以控制能够建立的连接数还能细粒度的控制到某个 server 的连接数,非常方便。在默认情况下,RestTemplate 到某个 server 的最大连接数只有 2, 一般需要调的更高些,最好等于 server 的 CPU 个数
-
access_token 不应传到 backend service. backend service 之间通信不需要 token,因为到这些服务的请求都是已经认证过的,是可信赖的用户发出的请求。因此转发请求时要把 parameter 从 request url 中删掉。删除 parameter 说难不难,说简单其实还有点麻烦,网上有一个 UrlEncodedQueryString 可以参考下,它封装了很多函数,其中就包括从url 中摘掉指定 header
-
请求的 HttpMethod 问题。 HttpMethod 有很多种,http client 不应该对每种 Http method 都单独处理,所以应选用 RestTemplate 的 exchange 方法。exchange 方法要求给出 RequestBody 参数,而对于 Get 请求,这部分往往为空,所以我们要在 controller 中声明 @RequestBody(required = false) String body
-
exchange 的返回值和 controller 的返回值。Restful API 一般都是返回 json 的,所以最简单的是 exchange 和 controller 直接返回 String,但是返回 String 会有很多问题: 首先是如果某些 API 返回的是图片,那么这个 client 就傻掉了,需要为图片接口专门写 API,此外如果 backend service 返回的是 Gzip,那么此 client 必须对 gzip 先解压缩再返回请求者,如果不解压缩的话,相当于对着 gzip 数据做了到 String 类型的强制转换,使得请求者拿到的数据无法解析,所以最好的返回值是 byte[]。对于那种比较大的 json 返回值,省去了对 String 的类型转换后还能带来很大的性能提升
-
关于返回值是 byte[] 还是 ResponseEntity<byte[]> 的问题。我觉得还是 ResponseEntity<byte[]> 好些,因为它就是 backend service 的结果。如果返回 byte[] 的话,还要对 HttpServletResponse 的 Header 进行修改,设置 Content-type, Content-encoding 等等。
https://www.cnblogs.com/xinsheng/p/5546221.html
Spring Boot忽略https证书:No subject alternative names present
springboot--resttemplate访问https请求
<!--http请求包--> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.3</version> </dependency>
import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.ssl.SSLContextBuilder; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; public class HttpClientUtils { public static CloseableHttpClient acceptsUntrustedCertsHttpClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { HttpClientBuilder b = HttpClientBuilder.create(); // setup a Trust Strategy that allows all certificates. // SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { return true; } }).build(); b.setSSLContext(sslContext); // don't check Hostnames, either. // -- use SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if you don't want to weaken HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; // here's the special part: // -- need to create an SSL Socket Factory, to use our weakened "trust strategy"; // -- and create a Registry, to register it. // SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", sslSocketFactory) .build(); // now, we create connection-manager using our Registry. // -- allows multi-threaded use PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager( socketFactoryRegistry); connMgr.setMaxTotal(200); connMgr.setDefaultMaxPerRoute(100); b.setConnectionManager( connMgr); // finally, build the HttpClient; // -- done! CloseableHttpClient client = b.build(); return client; } }
SpringBoot启动类添加配置
在启动类上配置RestTemplate(因为启动类也是配置类,比较方便)
@Bean public RestTemplate httpsRestTemplate(HttpComponentsClientHttpRequestFactory httpsFactory) { RestTemplate restTemplate = new RestTemplate(httpsFactory); restTemplate.setErrorHandler( new ResponseErrorHandler() { @Override public boolean hasError(ClientHttpResponse clientHttpResponse) { return false; } @Override public void handleError(ClientHttpResponse clientHttpResponse) { // 默认处理非200的返回,会抛异常 } }); return restTemplate; } @Bean(name = "httpsFactory") public HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory() throws Exception { CloseableHttpClient httpClient = HttpClientUtils.acceptsUntrustedCertsHttpClient(); HttpComponentsClientHttpRequestFactory httpsFactory = new HttpComponentsClientHttpRequestFactory(httpClient); httpsFactory.setReadTimeout(40000); httpsFactory.setConnectTimeout(40000); return httpsFactory; }
不出意外就可以愉快的访问https请求了!
---------------------
作者:别浪呀
来源:CSDN
原文:https://blog.csdn.net/adminBfl/article/details/84819735
版权声明:本文为博主原创文章,转载请附上博文链接!
https://*.com/questions/17619871/access-https-rest-service-using-spring-resttemplate
前面我们介绍了如何使用Apache的HttpClient发送HTTP请求,这里我们介绍Spring的Rest客户端(即:RestTemplate)
如何发送HTTP、HTTPS请求。注:HttpClient如何发送HTTPS请求,有机会的话也会再给出示例。
声明:本人一些内容摘录自其他朋友的博客,链接在本文末给出!
基础知识
微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端。我们可以使用JDK原生的URLConnection、Apache的Http Client、Netty的异步HTTP Client,最方便、最优雅的Feign, Spring的RestTemplate等。
RestTemplate简述
RestTemplate是Spring提供的用于访问Rest服务(Rest风格、Rest架构)的客户端。
RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
调用RestTemplate的默认构造函数,RestTemplate对象在底层通过使用java.net包下的实现创建HTTP 请求;我们也可以通过使用ClientHttpRequestFactory指定不同的请求方式:
ClientHttpRequestFactory接口主要提供了两种实现方式:
1.常用的一种是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)创建底层
的Http请求连接。
2.常用的另一种方式是使用HttpComponentsClientHttpRequestFactory方式,底层使用HttpClient访问远程的
Http服务,使用HttpClient可以配置连接池和证书等信息。
软硬件环境: Windows10、Eclipse、JDK1.8、SpringBoot
准备工作:引入相关依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
HTTP之GET请求(示例)
import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.client.RestTemplate; import com.google.gson.Gson; /** * 单元测试 * * @author JustryDeng * @DATE 2018年9月7日 下午6:37:05 */ @RunWith(SpringRunner.class) @SpringBootTest public class AbcHttpsTestApplicationTests { /** * RestTemplate 发送 HTTP GET请求 --- 测试 * @throws UnsupportedEncodingException * * @date 2018年7月13日 下午4:18:50 */ @Test public void doHttpGetTest() throws UnsupportedEncodingException { // -------------------------------> 获取Rest客户端实例 RestTemplate restTemplate = new RestTemplate(); // -------------------------------> 解决(响应数据可能)中文乱码 的问题 List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters(); converterList.remove(1); // 移除原来的转换器 // 设置字符编码为utf-8 HttpMessageConverter<?> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8); converterList.add(1, converter); // 添加新的转换器(注:convert顺序错误会导致失败) restTemplate.setMessageConverters(converterList); // -------------------------------> (选择性设置)请求头信息 // HttpHeaders实现了MultiValueMap接口 HttpHeaders httpHeaders = new HttpHeaders(); // 给请求header中添加一些数据 httpHeaders.add("JustryDeng", "这是一个大帅哥!"); // -------------------------------> 注:GET请求 创建HttpEntity时,请求体传入null即可 // 请求体的类型任选即可;只要保证 请求体 的类型与HttpEntity类的泛型保持一致即可 String httpBody = null; HttpEntity<String> httpEntity = new HttpEntity<String>(httpBody, httpHeaders); // -------------------------------> URI StringBuffer paramsURL = new StringBuffer("http://127.0.0.1:9527/restTemplate/doHttpGet"); // 字符数据最好encoding一下;这样一来,某些特殊字符才能传过去(如:flag的参数值就是“&”,不encoding的话,传不过去) paramsURL.append("?flag=" + URLEncoder.encode("&", "utf-8")); URI uri = URI.create(paramsURL.toString()); // -------------------------------> 执行请求并返回结果 // 此处的泛型 对应 响应体数据 类型;即:这里指定响应体的数据装配为String ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, httpEntity, String.class); // -------------------------------> 响应信息 //响应码,如:401、302、404、500、200等 System.err.println(response.getStatusCodeValue()); Gson gson = new Gson(); // 响应头 System.err.println(gson.toJson(response.getHeaders())); // 响应体 if(response.hasBody()) { System.err.println(response.getBody()); } } }
被http请求的对应的方法逻辑为:
注:我们也可以使用@RequestHeader()来获取到请求头中的数据信息,如:
结果(效果)展示
1.进行HTTP请求的方法获得响应后输出结果为:
2.被HTTP请求的方法被请求后的输出结果为:
HTTP之POST请求(示例)
/** * RestTemplate 发送 HTTP POST请求 --- 测试 * @throws UnsupportedEncodingException * * @date 2018年9月8日 下午2:12:50 */ @Test public void doHttpPostTest() throws UnsupportedEncodingException { // -------------------------------> 获取Rest客户端实例 RestTemplate restTemplate = new RestTemplate(); // -------------------------------> 解决(响应数据可能)中文乱码 的问题 List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters(); converterList.remove(1); // 移除原来的转换器 // 设置字符编码为utf-8 HttpMessageConverter<?> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8); converterList.add(1, converter); // 添加新的转换器(注:convert顺序错误会导致失败) restTemplate.setMessageConverters(converterList); // -------------------------------> (选择性设置)请求头信息 // HttpHeaders实现了MultiValueMap接口 HttpHeaders httpHeaders = new HttpHeaders(); // 设置contentType httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8); // 给请求header中添加一些数据 httpHeaders.add("JustryDeng", "这是一个大帅哥!"); // ------------------------------->将请求头、请求体数据,放入HttpEntity中 // 请求体的类型任选即可;只要保证 请求体 的类型与HttpEntity类的泛型保持一致即可 // 这里手写了一个json串作为请求体 数据 (实际开发时,可使用fastjson、gson等工具将数据转化为json串) String httpBody = "{\"motto\":\"唉呀妈呀!脑瓜疼!\"}"; HttpEntity<String> httpEntity = new HttpEntity<String>(httpBody, httpHeaders); // -------------------------------> URI StringBuffer paramsURL = new StringBuffer("http://127.0.0.1:9527/restTemplate/doHttpPost"); // 字符数据最好encoding一下;这样一来,某些特殊字符才能传过去(如:flag的参数值就是“&”,不encoding的话,传不过去) paramsURL.append("?flag=" + URLEncoder.encode("&", "utf-8")); URI uri = URI.create(paramsURL.toString()); // -------------------------------> 执行请求并返回结果 // 此处的泛型 对应 响应体数据 类型;即:这里指定响应体的数据装配为String ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.POST, httpEntity, String.class); // -------------------------------> 响应信息 //响应码,如:401、302、404、500、200等 System.err.println(response.getStatusCodeValue()); Gson gson = new Gson(); // 响应头 System.err.println(gson.toJson(response.getHeaders())); // 响应体 if(response.hasBody()) { System.err.println(response.getBody()); } }
被http请求的对应的方法逻辑为:
注:我们也可以使用@RequestHeader()来获取到请求头中的数据信息,如:
结果(效果)展示
进行HTTP请求的方法获得响应后输出结果为:
被HTTP请求的方法被请求后的输出结果为:
HTTPS请求的准备工作
HTTPS请求 = 超文本传输协议HTTP + 安全套接字层SSL。
先给出等下需要用到的一个SimpleClientHttpRequestFactory的实现类
/** * 声明:此代码摘录自https://blog.csdn.net/wltsysterm/article/details/80977455 * 声明:关于Socket的相关知识,本人会在后面的闲暇时间进行学习整理,请持续关注博客更新 * * @author JustryDeng * @DATE 2018年9月8日 下午4:34:02 */ public class HttpsClientRequestFactory extends SimpleClientHttpRequestFactory { @Override protected void prepareConnection(HttpURLConnection connection, String httpMethod) { try { if (!(connection instanceof HttpsURLConnection)) { throw new RuntimeException("An instance of HttpsURLConnection is expected"); } HttpsURLConnection httpsConnection = (HttpsURLConnection) connection; TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) { } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); httpsConnection.setSSLSocketFactory(new MyCustomSSLSocketFactory(sslContext.getSocketFactory())); httpsConnection.setHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String s, SSLSession sslSession) { return true; } }); super.prepareConnection(httpsConnection, httpMethod); } catch (Exception e) { e.printStackTrace(); } } /** * We need to invoke sslSocket.setEnabledProtocols(new String[] {"SSLv3"}); * see http://www.oracle.com/technetwork/java/javase/documentation/cve-2014-3566-2342133.html (Java 8 section) */ // SSLSocketFactory用于创建 SSLSockets private static class MyCustomSSLSocketFactory extends SSLSocketFactory { private final SSLSocketFactory delegate; public MyCustomSSLSocketFactory(SSLSocketFactory delegate) { this.delegate = delegate; } // 返回默认启用的密码套件。除非一个列表启用,对SSL连接的握手会使用这些密码套件。 // 这些默认的服务的最低质量要求保密保护和服务器身份验证 @Override public String[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites(); } // 返回的密码套件可用于SSL连接启用的名字 @Override public String[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } @Override public Socket createSocket(final Socket socket, final String host, final int port, final boolean autoClose) throws IOException { final Socket underlyingSocket = delegate.createSocket(socket, host, port, autoClose); return overrideProtocol(underlyingSocket); } @Override public Socket createSocket(final String host, final int port) throws IOException { final Socket underlyingSocket = delegate.createSocket(host, port); return overrideProtocol(underlyingSocket); } @Override public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort) throws IOException { final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort); return overrideProtocol(underlyingSocket); } @Override public Socket createSocket(final InetAddress host, final int port) throws IOException { final Socket underlyingSocket = delegate.createSocket(host, port); return overrideProtocol(underlyingSocket); } @Override public Socket createSocket(final InetAddress host, final int port, final InetAddress localAddress, final int localPort) throws IOException { final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort); return overrideProtocol(underlyingSocket); } private Socket overrideProtocol(final Socket socket) { if (!(socket instanceof SSLSocket)) { throw new RuntimeException("An instance of SSLSocket is expected"); } ((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1"}); return socket; } } }
HTTPS之GET请求
说明:RestTemplate发送HTTPS与发送HTTP的代码,除了在创建RestTemplate时不一样以及协议不一样
(一个URL是http开头,一个是https开头)外,其余的都一样。
HTTP获取RestTemplate实例
HTTPS获取RestTemplate实例
给出具体HTTPS发送GET请求代码示例(HTTPS发送POST请求类比即可)
注:HTTPS与HTTP的使用不同之处,在途中已经圈出了。
注:上图中请求的https://tcc.taobao.com/cc/json/mobile_tel_segment.htm是阿里提供的一个简单查询手机信息的地址。
运行该主函数,控制台打印出的结果为:
注:如果用HTTP协议开头的URL去访问HTTPS开头的URL的话(这两个URL除了协议不同其它都相同),是访问不了的;除非服
务端有相应的设置。
注:发送HTTPS的逻辑代码是可以拿来发送HTTP的。但是根据我们写得HttpsClientRequestFactory类中的代码可知,会打
印出异常(异常抛出后被catch了):
如果用HTTPS访问HTTP时不想抛出异常,那么把对应的这个逻辑去掉即可。
提示:“发送HTTPS的逻辑代码是可以拿来发送HTTP的”这句话的意思是:拿来做发HTTPS请求的逻辑,可以复用来作发HTTP请
求的逻辑。并不是说说一个API能被HTTPS协议的URL访问,就一定能被HTTP协议的URL访问。
HTTPS之GET请求
注:关于HTTPS这里只给出了一个GET示例,使用HTTPS进行POST请求也是与HTTP进行POST请求也只是创建
RestTemplate实例和协议不一样,其余的都一样;类比GET即可,这里就不再给出示例了。
参考链接、摘录内容出处
https://www.cnblogs.com/duanxz/p/3510622.html
https://blog.csdn.net/wltsysterm/article/details/80977455
https://blog.csdn.net/zhoumengshun/article/details/79100053
如有不当之处,欢迎指正
本次示例测试代码项目托管链接
https://github.com/JustryDeng/PublicRepository
本文已经被收录进《程序员成长笔记(三)》,笔者JustryDeng
---------------------
作者:justry_deng
来源:CSDN
原文:https://blog.csdn.net/justry_deng/article/details/82531306
版权声明:本文为博主原创文章,转载请附上博文链接!
spring boot resttemplate 使用及支持https协议
RestTemplate 使用
添加httpclient依赖
<!-- httpclient --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency>
配置类
package net.fanci.stars.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.client.RestTemplate; import java.util.Arrays; import java.util.List; /** * @author xxx * @create 2018/06/28 15:32 * @description RestTemplate配置类: * 1.将 HttpClient 作为 RestTemplate 的实现,添加 httpclient 依赖即可 * 2.设置响应类型和内容类型 */ @Configuration public class RestConfiguration { @Autowired private RestTemplateBuilder builder; @Bean public RestTemplate restTemplate() { return builder .additionalMessageConverters(new WxMappingJackson2HttpMessageConverter()) .build(); } class WxMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter { WxMappingJackson2HttpMessageConverter() { List<MediaType> mediaTypes = Arrays.asList( MediaType.TEXT_PLAIN, MediaType.TEXT_HTML, MediaType.APPLICATION_JSON_UTF8 ); setSupportedMediaTypes(mediaTypes);// tag6 } } }
使用方法(如:通过微信code获取token信息)
@Autowired private RestTemplate restTemplate; /** * 获取access_token的完整信息 * * @param code * @return */ @Override public WechatAuthAccesstoken getWechatAuthAccesstoken(String code) { String url = ACCESS_TOKEN_URL + "appid=" + wechatData.getAppID() + "&secret=" + wechatData.getAppsecret() + "&code=" + code + "&grant_type=authorization_code"; // com.alibaba.fastjson JSONObject jsonObject = restTemplate.getForObject(url, JSONObject.class); WechatAuthAccesstoken wechatAuthAccesstoken = new WechatAuthAccesstoken(); if (jsonObject != null) { wechatAuthAccesstoken.setId(PayUtil.genUniqueKey()); wechatAuthAccesstoken.setCreatedDate(DateTime.now().toDate()); wechatAuthAccesstoken.setModifiedDate(DateTime.now().toDate()); wechatAuthAccesstoken.setAccessToken((String) jsonObject.get("access_token")); DateTime now = DateTime.now(); DateTime expired = now.plusSeconds((Integer) jsonObject.get("expires_in")); wechatAuthAccesstoken.setExpires(expired.toDate()); wechatAuthAccesstoken.setRefreshToken(jsonObject.getString("refresh_token")); wechatAuthAccesstoken.setOpenid((String) jsonObject.get("openid")); wechatAuthAccesstoken.setScope(jsonObject.getString("scope")); int isOk = tokenMapper.insert(wechatAuthAccesstoken); if (isOk > 0) { logger.info("本地存储access_token信息成功"); return wechatAuthAccesstoken; } else { logger.error("本地存储access_token信息失败"); } } else { logger.error("获取access_token信息失败"); } return null; }
https支持
配置类
import org.springframework.http.client.SimpleClientHttpRequestFactory; import javax.net.ssl.*; import java.io.IOException; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.Socket; import java.security.cert.X509Certificate; /** * @author xxx * @create 2018/07/16 11:41 * @description 创建 HttpsClientRequestFactory 以支持 RestTemplate 调用 https 请求 */ public class HttpsClientRequestFactory extends SimpleClientHttpRequestFactory { @Override protected void prepareConnection(HttpURLConnection connection, String httpMethod) { try { if (!(connection instanceof HttpsURLConnection)) { throw new RuntimeException("An instance of HttpsURLConnection is expected"); } HttpsURLConnection httpsConnection = (HttpsURLConnection) connection; TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); httpsConnection.setSSLSocketFactory(new MyCustomSSLSocketFactory(sslContext.getSocketFactory())); httpsConnection.setHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String s, SSLSession sslSession) { return true; } }); super.prepareConnection(httpsConnection, httpMethod); } catch (Exception e) { e.printStackTrace(); } } /** * We need to invoke sslSocket.setEnabledProtocols(new String[] {"SSLv3"}); * see http://www.oracle.com/technetwork/java/javase/documentation/cve-2014-3566-2342133.html (Java 8 section) */ private static class MyCustomSSLSocketFactory extends SSLSocketFactory { private final SSLSocketFactory delegate; public MyCustomSSLSocketFactory(SSLSocketFactory delegate) { this.delegate = delegate; } @Override public String[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } @Override public Socket createSocket(final Socket socket, final String host, final int port, final boolean autoClose) throws IOException { final Socket underlyingSocket = delegate.createSocket(socket, host, port, autoClose); return overrideProtocol(underlyingSocket); } @Override public Socket createSocket(final String host, final int port) throws IOException { final Socket underlyingSocket = delegate.createSocket(host, port); return overrideProtocol(underlyingSocket); } @Override public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort) throws IOException { final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort); return overrideProtocol(underlyingSocket); } @Override public Socket createSocket(final InetAddress host, final int port) throws IOException { final Socket underlyingSocket = delegate.createSocket(host, port); return overrideProtocol(underlyingSocket); } @Override public Socket createSocket(final InetAddress host, final int port, final InetAddress localAddress, final int localPort) throws IOException { final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort); return overrideProtocol(underlyingSocket); } private Socket overrideProtocol(final Socket socket) { if (!(socket instanceof SSLSocket)) { throw new RuntimeException("An instance of SSLSocket is expected"); } ((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1"}); return socket; } } }
使用类
String message = null; String url = "https://ip:port/xxx"; RestTemplate restTemplateHttps = new RestTemplate(new HttpsClientRequestFactory()); List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(); StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName("UTF-8")); messageConverters.add(stringHttpMessageConverter); restTemplateHttps.setMessageConverters(messageConverters); ResponseEntity<String> responseEntity = restTemplateHttps.postForEntity(url, paramsData, String.class); if (responseEntity != null && responseEntity.getStatusCodeValue() == 200) { message = responseEntity.getBody(); }
离殇一曲与谁眠: 要依赖有什么用全是JDK和springboot自带的包
---------------------
作者:uanei
来源:CSDN
原文:https://blog.csdn.net/u013469944/article/details/84193792
版权声明:本文为博主原创文章,转载请附上博文链接!
1. 为什么使用HttpClient?
一开始其实是考虑使用RestTemplate的,但遇到的难题自然是SSL认证以及NTLM的认证.以目前的RestTemplate还做不到NTLM认证.而且使用SSL认证的过程也是挺复杂的. 复杂的是:居然还是要借助HttpClient .
@Bean public RestTemplate buildRestTemplate(List<CustomHttpRequestInterceptor> interceptors) throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); factory.setConnectionRequestTimeout(requestTimeout); factory.setConnectTimeout(connectTimeout); factory.setReadTimeout(readTimeout); // https SSLContextBuilder builder = new SSLContextBuilder(); builder.loadTrustMaterial(null, (X509Certificate[] x509Certificates, String s) -> true); SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(builder.build(), new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.2"}, null, NoopHostnameVerifier.INSTANCE); Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", new PlainConnectionSocketFactory()) .register("https", socketFactory).build(); PoolingHttpClientConnectionManager phccm = new PoolingHttpClientConnectionManager(registry); phccm.setMaxTotal(200); CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).setConnectionManager(phccm).setConnectionManagerShared(true).build(); factory.setHttpClient(httpClient); RestTemplate restTemplate = new RestTemplate(factory); List<ClientHttpRequestInterceptor> clientInterceptorList = new ArrayList<>(); for (CustomHttpRequestInterceptor i : interceptors) { ClientHttpRequestInterceptor interceptor = i; clientInterceptorList.add