背景
现在需要请求一个https的接口,是请求docker仓库所有镜像的,但是接口需要账户密码验证,并不是那种Get里写username、password的方式,行不通,需要这种方式写
https://abcd:123456@mydocker.beacool.com/v2/_catalog
这种写法呢,我也是第一次见,帐户名:abcd, 密码:123456,这个url直接放在谷歌浏览器上会弹出输入账户密码,然后输入账户密码就行了
图片.png
用postman也可以运行,但是昨天可以的,今天突然就不行了。。。。WTF???
本来呢,我是打算用vue写前端调用的,但是有跨域问题解决不了,那只能用Java写了
开始
好嘛,本以为是个很简单的http/https请求,
1然后用普通的HttpClient发现不行,教程网上一堆!
2用springboot的Resttemplate,发起get请求也不行!!
参考 https://blog.csdn.net/xiekuntarena/article/details/82108795
3然后各种百度,发现这是权限问题,账户密码直接写在url里不行,账户密码要写在UsernamePasswordCredentials类里,发现依然不行!!!!!!!
参考 https://blog.csdn.net/qq_15783243/article/details/78684423
和 https://www.cnblogs.com/diyunpeng/p/4394373.html
//该网页需要认证(用户名、密码)
HttpClientContext context = new HttpClientContext();
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("beacool", "beacool4321"));
context.setCredentialsProvider(credentialsProvider);
CloseableHttpResponse execute = client.execute(get, context);
以上方法对于一般的url都是可以的,但是对我这种(变态的)url都不行,全部报如下错误
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
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1611)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:187)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:181)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1035)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:124)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:516)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:454)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:884)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1112)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1139)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1123)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.https.HttpsURLConne
解决办法
pom文件,jdk1.8(1.6以上就行)
org.apache.httpcomponents
httpclient
4.5.2
通用类代码
package com.beacool;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
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.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
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.util.EntityUtils;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* 发起http、https请求,
* 发起https请求时会信任所有证书
* 支持带有账户密码验证的URL,如这种URL:https://abc:1234@www.aaaa.com/v2/_catalog
*/
public class HttpsClientUtil {
private static CloseableHttpClient acceptsUntrustedCertsHttpClient() throws Exception {
HttpClientBuilder b = HttpClientBuilder.create();
//内部类
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
return true;
}
}).build();
b.setSslcontext( sslContext);
// 不获取主机名
// 如果您不想削弱,请使用sslconnectionsocketfactory.getdefaulthostnameverfier()
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
// 特殊部分:
// -- 创建SSL套接字工厂,以使用我们削弱的“信任策略”。
// -- 创建一个注册表注册它
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext,hostnameVerifier);
Registry socketFactoryRegistry = RegistryBuilder.create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https",sslSocketFactory)
.build();
/*创建一个http客户端连接管理池
* 现在,我们使用注册表创建连接管理器。
允许多线程的使用*/
PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
b.setConnectionManager( connMgr);
// 最后,创建一个httpclient类
CloseableHttpClient client = b.build();
return client;
}
/**
*
* @param url https://....
* @param jsonStr 数据
* @param charset 字符集
* @return
*/
public static String doPost(String url, String jsonStr, String charset){
HttpClient httpClient = null;
HttpPost httpPost = null;
String result = null;
try{
httpClient = acceptsUntrustedCertsHttpClient(); //jdk1.6用法
//httpClient = new SSLClient(); //一般用法
httpPost = new HttpPost(url);
StringEntity entity = new StringEntity(jsonStr,charset);
httpPost.setEntity(entity);
HttpResponse response = httpClient.execute(httpPost);
if(response != null){
HttpEntity resEntity = response.getEntity();
if(resEntity != null){
result = EntityUtils.toString(resEntity,charset);
}
}
}catch(Exception ex){
ex.printStackTrace();
}
return result;
}
public static String doGet(String url){
HttpClient httpClient = null;
HttpGet httpGet = null;
String result = null;
try{
httpClient = acceptsUntrustedCertsHttpClient(); //jdk1.6用法
//httpClient = new SSLClient(); //一般用法
httpGet = new HttpGet(url);
HttpResponse response = httpClient.execute(httpGet);
if(response != null){
HttpEntity resEntity = response.getEntity();
if(resEntity != null){
result = EntityUtils.toString(resEntity);
}
}
}catch(Exception ex){
ex.printStackTrace();
}
System.out.println("========="+result);
return result;
}
}
调用方式
HttpsClientUtil.doGet("https://abcd:123456@mydocker.beacool.com/v2/_catalog");
//这个你们可以直接拿来测试
HttpsClientUtil.doGet("https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13524017352");
这个通用类可以说是很牛皮了,支持所有类型的url,不管是http还是https. POST、GET都行