需求
Java代码基于JDK1.6,需要调用https接口,且contentType类型为MULTIPART_FORM_DATA。
实现
在实现上面的需求时遇到两个问题,找到解决方法费了点时间。
所以在此记录下来,希望给遇到同样问题的同学一点启发。请看第一版代码:
public static void main(String[] args) {
String url = "https://10.22.1.50:443/workorder/subUrlInterface";
String param = "value";
HttpUtils.doPostWithFormData(url, param);
}
public static void doPostWithFormData(String url, String param){
CloseableHttpClient client = null;
HttpPost post = buildPost(url, param);
try {
client = HttpClients.createDefault();
HttpResponse response = client.execute(post);
if(response.getStatusLine().getStatusCode() == 200){
HttpEntity httpEntity = response.getEntity();
String responseContent = EntityUtils.toString(httpEntity, "UTF-8");
System.out.println("response is:" + responseContent);
}else {
System.out.println("response code is:" + response.getStatusLine().getStatusCode());
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(client != null){
client.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
private static HttpPost buildPost(String url, String param){
HttpPost post = new HttpPost(url);
HttpEntity multipart = buildEntity(param);
post.setEntity(multipart);
return post;
}
private static HttpEntity buildEntity(String param){
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
ContentType type = ContentType.create("multipart/form-data", Charset.forName("UTF-8"));
builder.addTextBody("data", param, type);
return builder.build();
}
执行上面代码的错误提示是:
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
在网上搜到的解决方案是:修改CloseableHttpClient的初始化方式。修改后的初始化代码是:
............
// 创建一个不验证证书的 httpClient
client = createHttpClient();
............
private static CloseableHttpClient createHttpClient() throws Exception{
SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) {
return true;
}
}).build();
SSLConnectionSocketFactory sslSf = new SSLConnectionSocketFactory(sslcontext, null, null,
new NoopHostnameVerifier());
return HttpClients.custom().setSSLSocketFactory(sslSf).build();
}
如果代码是基于JDK1.8的话,那么这个问题就算解决了。但是在JDK1.6中,还是会报错:
javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair
在网上搜到的解决方案是:扩展java.security,引入bcprov-jdk15on-1.60.jar。将下面的这行代码放在发送post请求前。
Security.insertProviderAt(new BouncyCastleProvider(), 1);
至此,调用https接口正常。
依赖
- httpclient-4.5.10.jar
- httpcore-4.4.12.jar
- httpmime-4.5.11.jar
- bcprov-jdk15on-1.60.jar
- commons-logging-1.2.jar
- slf4j-api-1.7.1.jar
请求配置
上面的示例代码中没有体现出发送请求时的配置,如超时时间等。具体配置可参考下面的代码:
private static RequestConfig requestConfig;
static {
// http 连接配置
RequestConfig.Builder configBuilder = RequestConfig.custom();
configBuilder.setConnectTimeout(3000);
configBuilder.setSocketTimeout(3000);
configBuilder.setConnectionRequestTimeout(3000);
configBuilder.setExpectContinueEnabled(true);
requestConfig = configBuilder.build();
}
............
HttpPost post = new HttpPost(url);
post.setConfig(requestConfig);
............
参考资料:
- https://www.javaear.com/question/40381968.html
- https://www.cnblogs.com/moy25/p/8658762.html
- https://www.jianshu.com/p/d6ab78e4ed73
- https://blog.csdn.net/qq441568267/article/details/77715624
- https://docs.oracle.com/javase/6/docs/api/