場景:
認證服務器須要有個 http client 把前端發來的請求轉發到 backend service, 而後把 backend service 的結果再返回給前端,服務器自己只作認證功能。html
遇到的問題:
-
長鏈接以保證高性能。RestTemplate 自己也是一個 wrapper 其底層默認是 SimpleClientHttpRequestFactory ,若是要保證長鏈接, HttpComponentsClientHttpRequestFactory 是個更好的選擇,它不只能夠控制可以創建的鏈接數還能細粒度的控制到某個 server 的鏈接數,很是方便。在默認狀況下,RestTemplate 到某個 server 的最大鏈接數只有 2, 通常須要調的更高些,最好等於 server 的 CPU 個數前端
-
access_token 不該傳到 backend service. backend service 之間通訊不須要 token,由於到這些服務的請求都是已經認證過的,是可信賴的用戶發出的請求。所以轉發請求時要把 parameter 從 request url 中刪掉。刪除 parameter 說難不難,說簡單其實還有點麻煩,網上有一個 UrlEncodedQueryString 能夠參考下,它封裝了不少函數,其中就包括從url 中摘掉指定 headerjava
-
請求的 HttpMethod 問題。 HttpMethod 有不少種,http client 不該該對每種 Http method 都單獨處理,因此應選用 RestTemplate 的 exchange 方法。exchange 方法要求給出 RequestBody 參數,而對於 Get 請求,這部分每每爲空,因此咱們要在 controller 中聲明 @RequestBody(required = false) String bodygit
-
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
github
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啓動類添加配置web
在啓動類上配置RestTemplate(由於啓動類也是配置類,比較方便) spring
@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請求了!apache
---------------------
做者:別浪呀
來源:CSDN
原文:https://blog.csdn.net/adminBfl/article/details/84819735
版權聲明:本文爲博主原創文章,轉載請附上博文連接!json
https://stackoverflow.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能夠配置鏈接池和證書等信息。
軟硬件環境: Windows十、Eclipse、JDK1.八、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);
// -------------------------------> 響應信息
//響應碼,如:40一、30二、40四、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);
// -------------------------------> 響應信息
//響應碼,如:40一、30二、40四、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(interceptor