JAVA调用HTTPS接口


概述

本文主要介绍JAVA实现https接口调用包括忽略本地证书方式和加载本地证书方式两种.

第一种:忽略本地证书方式

忽略本地证书方式就是服务器不对客户端证书做校验的网站比如 www.baidu.com,
和其他https网站不一样,其他网站需要客户端本地拥有证书文件,在客户端调用的时候加载.

1.编写HttpClientUtil工具类

    import org.apache.commons.lang.StringUtils;
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.message.BasicHeader;
    import org.apache.http.params.CoreConnectionPNames;
    import org.apache.http.util.EntityUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    /**
     * 
    * @Description:    利用HttpClient进行post请求的工具类
    * @author: jackromer
    * @version: 1.0, Jan 25, 2019
     */
    @SuppressWarnings("deprecation")
    public class HttpClientUtil {
        public static final Logger        logger    = LoggerFactory.getLogger(HttpClientUtil.class);

        /**
         * 发送post消息
        * @Description:
        * @param url
        * @param jsonstr
        * @param charset
        * @return
         */
        public static void doPost(String url,String jsonstr,String charset){
            logger.info("POST MESSAGE:" + jsonstr);
            HttpClient httpClient = null;
            HttpPost httpPost = null;
            String result = null;
            try {
                httpClient = new SSLClient();
                httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);
                httpPost = new HttpPost(url);
                httpPost.addHeader("Content-Type", "application/json");
                StringEntity se = new StringEntity(jsonstr);
                se.setContentType("text/json");
                se.setContentEncoding(new BasicHeader("Content-Type", "application/json"));
                httpPost.setEntity(se);
                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();
                logger.error("POST MSG ERROR.", ex);
            }

            if (!StringUtils.isEmpty(result)) {
                logger.info("POST  RESULT:" + result);
            } else {
                logger.error("POST RESULT IS NULL.");
            }
        }

    }

2.编写https的SSLClient类

    /**
    * @Description:    用于进行Https请求的HttpClient  
    * @author: jackromer
    * @version: 1.0, Jan 24, 2019
    */

    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;

    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;

    import org.apache.http.conn.ClientConnectionManager;
    import org.apache.http.conn.scheme.Scheme;
    import org.apache.http.conn.scheme.SchemeRegistry;
    import org.apache.http.conn.ssl.SSLSocketFactory;
    import org.apache.http.impl.client.DefaultHttpClient;  

    @SuppressWarnings("deprecation")
    public class SSLClient extends DefaultHttpClient{  

        public SSLClient() throws Exception{  
            super();  
            SSLContext ctx = SSLContext.getInstance("TLS");  
            X509TrustManager tm = new X509TrustManager() {  
                    @Override  
                    public void checkClientTrusted(X509Certificate[] chain,  
                            String authType) throws CertificateException {  
                    }  
                    @Override  
                    public void checkServerTrusted(X509Certificate[] chain,  
                            String authType) throws CertificateException {  
                    }  
                    @Override  
                    public X509Certificate[] getAcceptedIssuers() {  
                        return null;  
                    }  
            };  

            ctx.init(null, new TrustManager[]{tm}, null);  
            HostnameVerifier ignoreHostnameVerifier = new HostnameVerifier() {
                public boolean verify(String s, SSLSession sslsession) {
                    System.out.println("WARNING: Hostname is not matched for cert.");//忽略本地证书文件校验
                    return true;
                }
            };
            HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier);
            HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());

            SSLSocketFactory ssf = new SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);  
            ClientConnectionManager ccm = this.getConnectionManager();  
            SchemeRegistry sr = ccm.getSchemeRegistry();  
            sr.register(new Scheme("https", 443, ssf));  
        }  
    }  

3. 创建POST请求测试

      public static void main(String[] args) {
            String httpsUrl = "https://ip:post/restName";
            String postJson = "{\"test\":\"hello\"}";
            HttpClientUtil.doPost(httpsUrl, postJson, "utf-8");
        }

第二种:加载本地证书和key的方式

1.创建httpsClient

    /**
    * @Description:    
    * @author: zhouqiang
    * @version: 1.0, Jan 25, 2019
    */
    @SuppressWarnings("unchecked")
    public class HttpsClient {
        private static String CONTENT_LENGTH = "Content-Length";

        private CloseableHttpClient closeableHttpClient;

        /**
         * 初始化证书
         */
        public void initSSLConfig(){

            try {
                //加载证书
                InputStream selfInputStream = HttpsClient.class.getClassLoader().getResourceAsStream(GatewayNbConstants.PKCS12_PATH);//PKCS12文件地址
                InputStream caInputStream = HttpsClient.class.getClassLoader().getResourceAsStream(GatewayNbConstants.JKS_PATH);//JKS证书文件地址
                if (selfInputStream == null || caInputStream == null){
                    return;
                }

                KeyStore pksKeyStore = KeyStore.getInstance("pkcs12");
                pksKeyStore.load(selfInputStream, GatewayNbConstants.PKCS12_PASSWORD.toCharArray());
                selfInputStream.close();

                KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("sunx509");
                keyManagerFactory.init(pksKeyStore, GatewayNbConstants.PKCS12_PASSWORD.toCharArray());//PKCS12的密码

                KeyStore jksKeyStore = KeyStore.getInstance("jks");
                jksKeyStore.load(caInputStream, GatewayNbConstants.JKS_PASSWORD.toCharArray());//JKS的密码
                caInputStream.close();

                TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("sunx509");
                trustManagerFactory.init(jksKeyStore);

                SSLContext sslContext = SSLContext.getInstance("TLS");
                sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());

                SSLConnectionSocketFactory ssf = new SSLConnectionSocketFactory(sslContext, new HostnameVerifier() {
                    @Override
                    public boolean verify(String s, SSLSession sslSession) {
                        return true;
                    }
                });

                closeableHttpClient = HttpClients.custom().setSSLSocketFactory(ssf).build();
            }catch (Exception en){
                en.printStackTrace();
            }
        }

        /**
         * @Description: post请求
         * @param url https路径
         * @param headerMap  请求头信息
         * @param params 请求参数
         * @param contentType 请求类型
         * @return CloseableHttpResponse
         */
        public CloseableHttpResponse post(String url, Map<String, String> headerMap, String params, ContentType contentType) throws IOException{
            HttpPost request = new HttpPost(url);

            addRequestHeader(request, headerMap);

            request.setEntity(new StringEntity(params, contentType));

            return closeableHttpClient.execute(request);
        }

        /**
         * @Description: post请求
         * @param url https路径
         * @param params 请求参数
         * @return CloseableHttpResponse
         */

        @SuppressWarnings("rawtypes")
        public CloseableHttpResponse post(String url,  List params) throws IOException{
            HttpPost request = new HttpPost(url);

            request.setEntity(new UrlEncodedFormEntity(params, "utf-8"));

            return closeableHttpClient.execute(request);
        }

      /**
         * 添加请求头参数
        * @Description:
        * @param request
        * @param headerMap
         */

        private void addRequestHeader(HttpUriRequest request, Map<String, String> headerMap) {
            if (headerMap == null) {
                return;
            }

            for (String headerName : headerMap.keySet()) {
                if (CONTENT_LENGTH.equalsIgnoreCase(headerName)) {
                    continue;
                }

                request.addHeader(headerName, headerMap.get(headerName));
            }
        }
    }

2.加载p12文件

如果使用的是springboot,则需要在application.properties文件中添加如下配置,这是为了让springboot启动时自动加载这些参数和文件到springboot context中去.具体配置可参照springboot官网对HTTPS SSL的支持.

    server.ssl.key-store-type=PKCS12

    server.ssl.key-store=classpath:server.p12 #server.p12文件最好放在更目录中以保证springboot加载正确.

    server.ssl.key-store-password=yourpassword

3.编写TestService发送post请求

    import java.io.IOException;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;

    import org.apache.http.HttpEntity;
    import org.apache.http.NameValuePair;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.entity.ContentType;
    import org.apache.http.message.BasicNameValuePair;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.HttpStatus;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Component;

    import com.fasterxml.jackson.databind.node.ObjectNode;
    import com.sefon.gateway.NbHuaweiHttpsModule.common.HttpsClient;
    import com.sefon.gateway.NbHuaweiHttpsModule.utils.StreamUtil;


    /**
    * @Description:    
    * @author: jackromer
    * @version: 1.0, Jan 25, 2019
    */
    @Component
    @SuppressWarnings("unchecked")
    public class TestService {
        private static final Logger logger = LoggerFactory.getLogger(TestService.class);

        private HttpsClient httpsClient;

        public TestService(){
            this.httpsClient = new HttpsClient();
            this.httpsClient.initSSLConfig();
        }

        /**
         * 用list参数请求
        * @Description:
         */
        @SuppressWarnings("rawtypes")
        public void postList(){
            try {
                String postUrl = null;//your post url
                List<NameValuePair> postParas = new LinkedList();
                postParas.add(new BasicNameValuePair("name1","value1"));
                postParas.add(new BasicNameValuePair("name2","value2"));
                CloseableHttpResponse response = httpsClient.post(postUrl, postParas);
                String responseBody = getResponseContent(response);
                logger.info("post result", responseBody);
            } catch (Exception en) {
                logger.error("post error", en);
            }
        }

        /**
         * 用json或其他类型请求
        * @Description:
        * @param postJson
         */
        @SuppressWarnings("rawtypes")
        @Async
        public void postJsonStr(ObjectNode postJson){
            try {
                //封装应用命令下发的头信息
                String postUrl = null;//your post url
                Map headers = null;//your header
                      CloseableHttpResponse httpResponse = httpsClient.post(postUrl, headers, postJson.toString(), ContentType.APPLICATION_JSON);
                int statusCode = httpResponse.getStatusLine().getStatusCode();
                if (statusCode == HttpStatus.CREATED.value()){
                    logger.info("post success");
                }
            } catch (Exception en){
                en.printStackTrace();
            }
        }

        /**
         * 获取返回数据
        * @Description:
        * @param closeableHttpResponse
        * @return
        * @throws IOException
         */
        private String getResponseContent(CloseableHttpResponse closeableHttpResponse) throws IOException {
            String content = null;
            if (closeableHttpResponse != null){
                try {
                    HttpEntity httpEntity = closeableHttpResponse.getEntity();
                    if (httpEntity != null && httpEntity.isStreaming()){
                        String encoding = httpEntity.getContentEncoding() != null ? httpEntity.getContentEncoding().getValue() : null;
                        content = StreamUtil.inputStream2String(httpEntity.getContent(), encoding);
                    }
                } finally {
                    closeableHttpResponse.close();
                }
            }
            return content;
        }
    }

4. 测试TestService发送请求

    import java.io.IOException;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import com.sefon.gateway.NbHuaweiHttpsModule.service.TestService;

    /**
    * @Description:    
    * @author: jackromer
    * @version: 1.0, Jan 25, 2019
    */
    @Component
    public class TestPost {

        @Autowired
        private  TestService testService;

        /**
         * 通过TestService 调用https接口
        * @Description:
         */
        public void post() throws IOException{
            try {
                //testService.postList();
                testService.postJsonStr(null);//your json Str
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    }

总结

以上就是JAVA调用https的两种方式,第一种不需要验证本地证书,第二种则为混合加密方式,需要验证本地证书和key是否正确。



   Reprint policy


《JAVA调用HTTPS接口》 by jackromer is licensed under a Creative Commons Attribution 4.0 International License
 Previous
HTTP和HTTPS的区别 HTTP和HTTPS的区别
概述本文主要介绍JAVA对https的支持,为何使用https呢,https相当于是http的升级版本,具有http不具备的安全性. 什么是https HTTPS(全称:Hyper Text Transfer Protocol over
2019-08-27
Next 
Linux自动打包脚本 Linux自动打包脚本
概述 本文主要介绍如何使用一些linux脚本 linux启动项目脚本 启动脚本名startup.bash #!/bin/bash start_monitor() { nohup java -cp KafkaOffsetMon
2019-08-27
  目录