我正在使用restTemplate请求SSL发布。问题是我无法通过SSL向服务器发送发布请求。我正在使用自签名证书进行通信。但是,奇怪的是,当我通过SSL发送get请求时,它工作正常。
我不知道为什么POST不像GET那样不起作用。这是我使用restTemplate进行的GET和POST。
public <T> T getByRestTemplate(String url, Object param, boolean isSSL, String token, ParameterizedTypeReference<T> responseType) throws RestClientException {
HttpEntity<Object> requestEntity = makeHttpEntity(param, token);
RestTemplate restTemplate = buildRestTemplate(isSSL);
ResponseEntity<T> responseEntity;
responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, responseType);
return responseEntity.getBody();
}
public <T> T postByRestTemplate(String url, Object param, boolean isSSL, String token, Class<T> responseType) throws RestClientException {
HttpEntity<Object> requestEntity = makeHttpEntity(param, token);
RestTemplate restTemplate = prepareRestTemplate(isSSL);
ResponseEntity<T> responseEntity;
responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, responseType);
return responseEntity.getBody();
}
private RestTemplate prepareRestTemplate(boolean isSSL){
int connectTimeOut = (appConfigProperties.getConnectTimeOut()!=0)?appConfigProperties.getConnectTimeOut():5000;
int readTimeOut = (appConfigProperties.getReadTimeOut()!=0)?appConfigProperties.getConnectTimeOut():5000;
RestTemplate restTemplate = buildRestTemplate(isSSL);
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setConnectTimeout(connectTimeOut);
requestFactory.setReadTimeout(readTimeOut);
restTemplate.setRequestFactory(requestFactory);
return restTemplate;
}
private RestTemplate buildRestTemplate(boolean isSSL) {
RestTemplate restTemplate = null;
if (isSSL) {
try {
restTemplate = restTemplateSSL.restTemplateSSL();
} catch (Exception e) {
e.printStackTrace();
}
} else {
restTemplate = restTemplateBuilder.build();
}
return restTemplate;
}
这里是与SSL设置相关的代码。
private static TrustManager[] createTrustManagers() {
TrustManager[] trustAllCerts;
trustAllCerts = new TrustManager[]{new X509ExtendedTrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s){
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) {
}
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) {
}
}};
return trustAllCerts;
}
public RestTemplate restTemplateSSL() throws Exception {
SSLContext sslContext = SSLContext.getInstance(SSL_TLS);
sslContext.init(null, createTrustManagers(), new java.security.SecureRandom());
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext,
NoopHostnameVerifier.INSTANCE);
final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register(SSL_HTTPS, csf)
.build();
final PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.setConnectionManager(cm)
.build();
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return new RestTemplate(requestFactory);
}
这是我得到的日志。
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target] with root cause
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) ~[na:1.8.0_192]
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) ~[na:1.8.0_192]
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) ~[na:1.8.0_192]
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392) ~[na:1.8.0_192]
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302) ~[na:1.8.0_192]
at sun.security.validator.Validator.validate(Validator.java:262) ~[na:1.8.0_192]
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) ~[na:1.8.0_192]
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229) ~[na:1.8.0_192]
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124) ~[na:1.8.0_192]
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621) ~[na:1.8.0_192]
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223) ~[na:1.8.0_192]
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037) ~[na:1.8.0_192]
at sun.security.ssl.Handshaker.process_record(Handshaker.java:965) ~[na:1.8.0_192]
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064) ~[na:1.8.0_192]
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367) ~[na:1.8.0_192]
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395) ~[na:1.8.0_192]
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379) ~[na:1.8.0_192]
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:436) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:384) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:374) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56) ~[httpclient-4.5.9.jar:4.5.9]
at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:87) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:735) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:670) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:579) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
我已经阅读了许多其他帖子和stackoverflow问答
Access Https Rest Service using Spring RestTemplate
How to disable SSL certificate checking with Spring RestTemplate?
Disabling SSL Certificate Validation in Spring RestTemplate
以及有关此问题的更多信息。但是都没有解决。我不确定我还能怎么尝试。
毕竟这是一个愚蠢的错误。
设置POST请求的restClient时,我犯了一个覆盖RequestFactory的错误,因此删除了SSL连接的先前设置。
希望没有人会犯这种错误!