RestTemplate在访问https资源时,出现报错
java.security.cert.CertificateException: No subject alternative names matching IP address ******* found;
该问题主要是由于https请求时需要服务侧提供的证书认证,如果没有证书的话,可通过以下方法来信任请求:
一、通过CloseableHttpClient来信任所有https的请求(绕过证书认证)
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.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
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 {
/**
* CloseableHttpClient 信任所有https请求
*
* @return
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
public static CloseableHttpClient acceptsUntrustedCertsHttpClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
HttpClientBuilder b = HttpClientBuilder.create();
// 设置信任所有证书
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
return true;
}
}).build();
b.setSSLContext(sslContext);
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslSocketFactory)
.build();
PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connMgr.setMaxTotal(200);
connMgr.setDefaultMaxPerRoute(100);
b.setConnectionManager(connMgr);
CloseableHttpClient client = b.build();
return client;
}
}
二、 配置RestTemplate实例
import com.eastcom.intsight.fault.intellect.collect.util.HttpClientUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean(name = "restTemplate")
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(2000);
httpsFactory.setConnectTimeout(2000);
return httpsFactory;
}
}
三、 附上自己封装的RestTemplate工具类
import com.*.enums.BizExceptionCodeEnum;
import com.*.enums.ResultCodeEnum;
import com.*.exception.BizException;
import com.*.model.Result;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.Map;
@Service
@Slf4j
public class InvokingService {
@Resource(name = "restTemplate")
private RestTemplate restTemplate;
/**
* 服务调用,返回响应Body
*
* @param url
* @param type
* @param paramType 参数类型,若是post请求,且参数类型为'@RequestBody'时,需特殊处理
* @param headerMap 参数类型,若是post请求,且参数类型为'@RequestBody'时,需特殊处理
* @param paramMap 参数类型为'@RequestBody'时,参数Map中只放一个随意key即可,值为JSON字符串参数
* @return
*/
public String invServiceForResultData(String url, String type, String paramType, Map<String, String> headerMap, Map<String, String> paramMap) {
try {
String resultObj = "";
HttpEntity requestEntity = buildRequestEntity(paramType, headerMap, paramMap);
if ("GET".equalsIgnoreCase(type)) {
resultObj = restTemplate.getForObject(url, String.class);
} else if ("POST".equalsIgnoreCase(type)) {
resultObj = restTemplate.postForObject(url, requestEntity, String.class);
} else if ("PUT".equalsIgnoreCase(type) || "DELETE".equalsIgnoreCase(type)) {
ResponseEntity<String> responseEntity = restTemplate.exchange(url, choiceHttpMethod(type), requestEntity, String.class);
resultObj = responseEntity.getBody();
}
return resultObj;
} catch (Exception e) {
JSONObject errorObj = new JSONObject();
errorObj.put("url", url);
errorObj.put("type", type);
Result result = new Result(ResultCodeEnum.C505, errorObj);
return JSONObject.fromObject(result).toString();
}
}
/**
* 服务调用,返回响应体,可获取所有响应信息,如响应头,响应code等
*
* @param url
* @param type
* @param paramType
* @param headerMap
* @param paramMap
* @return
*/
public ResponseEntity<String> invServiceForResultEntity(String url, String type, String paramType, Map<String, String> headerMap, Map<String, String> paramMap) {
try {
ResponseEntity<String> responseEntity = null;
HttpEntity requestEntity = buildRequestEntity(paramType, headerMap, paramMap);
responseEntity = restTemplate.exchange(url, choiceHttpMethod(type), requestEntity, String.class);
return responseEntity;
} catch (Exception e) {
e.printStackTrace();
JSONObject errorObj = new JSONObject();
errorObj.put("url", url);
errorObj.put("type", type);
throw new BizException(BizExceptionCodeEnum.INVOKING_ERROR, errorObj.toString());
}
}
/**
* 构建http请求配置
*
* @param paramType
* @param headerMap
* @param paramMap
* @return
*/
public HttpEntity buildRequestEntity(String paramType, Map<String, String> headerMap, Map<String, String> paramMap) {
HttpEntity requestEntity = null;
HttpHeaders headers = setHeaders(headerMap);
if ("BODY".equalsIgnoreCase(paramType)) {
headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
String param = "";
if (null != paramMap) {
for (Map.Entry<String, String> entry : paramMap.entrySet()) {
param = entry.getValue();
break;
}
}
requestEntity = new HttpEntity(JSONObject.fromObject(param), headers);
} else {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
if (null != paramMap) {
for (Map.Entry<String, String> entry : paramMap.entrySet()) {
params.add(entry.getKey(), entry.getValue());
}
}
requestEntity = new HttpEntity(params, headers);
}
return requestEntity;
}
/**
* 设置请求头部信息
*
* @param headerMap
* @return
*/
public HttpHeaders setHeaders(Map<String, String> headerMap) {
HttpHeaders headers = new HttpHeaders();
if (null == headerMap) {
return headers;
}
for (Map.Entry<String, String> entry : headerMap.entrySet()) {
headers.set(entry.getKey(), entry.getValue());
}
return headers;
}
/**
* 选择请求方式
*
* @param type
* @return
*/
public HttpMethod choiceHttpMethod(String type) {
if ("GET".equalsIgnoreCase(type)) {
return HttpMethod.GET;
} else if ("POST".equalsIgnoreCase(type)) {
return HttpMethod.POST;
} else if ("PUT".equalsIgnoreCase(type)) {
return HttpMethod.PUT;
} else if ("DELETE".equalsIgnoreCase(type)) {
return HttpMethod.DELETE;
} else if ("HEAD".equalsIgnoreCase(type)) {
return HttpMethod.HEAD;
} else if ("PATCH".equalsIgnoreCase(type)) {
return HttpMethod.PATCH;
} else if ("OPTIONS".equalsIgnoreCase(type)) {
return HttpMethod.OPTIONS;
} else if ("TRACE".equalsIgnoreCase(type)) {
return HttpMethod.TRACE;
} else {
return HttpMethod.POST;
}
}
}