OKHttp使用demo(證書過濾,證書導入,代理訪問,文件上傳)


此demo需要引入okhttp-3.4.1.jar 和 okio-1.9.0.jar(這兩個包需要jdk1.7以上的環境)

對應pom文件是:

		<dependency>
			<groupId>com.squareup.okhttp3</groupId>
			<artifactId>okhttp</artifactId>
			<version>3.4.1</version>
		</dependency>

 demo文件:HttpClientManage.java 其中的一些日志打印需要替換下

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.FormBody.Builder;
import okhttp3.OkHttpClient;
import okhttp3.Request;

import org.apache.commons.lang.StringUtils;

import test2.LogUtil;

/**
 * OkHttp官方文檔並不建議我們創建多個OkHttpClient,因此全局使用一個。 
 * 支持自動讀取配置文件中的過期時間配置以及CA導入,或采用默認配置
 * 支持實現同步請求(普通+快速),異步請求(普通+快速)
 * 支持頭文件設置
 * 支持https
 * 支持代理ip port 若未設置代理ip等信息則采用本機ip常規方式進行請求
 * @date 2017年6月10日 下午5:07:14
 */
public class HttpClientManage
{
    private static volatile HttpClientManage instance;

    private static int CONNECT_TIMEOUT = 60;
    private static int READ_TIMEOUT = 100;
    private static int WRITE_TIMEOUT = 60;
    private static int CONNECT_TIMEOUT_QUICK = 3;
    private static int READ_TIMEOUT_QUICK = 5;
    private static int WRITE_TIMEOUT_QUICK = 3;
    /**
     * ca證書存放路徑
     */
    private static String CA_PATH = null;
    /**
     * 代理域名或者IP
     */
    private static String PROXY_IP = null;
    /**
     * 代理端口
     */
    private static int PROXY_PORT = 80;
    /**
     * 是否忽略正式
     */
    private static boolean IS_INORE_CA = true;

    private static String PARAM_SPLIT_FIRST = "?";
    private static String PARAM_SPLIT_VAL = "=";
    private static String PARAM_SPLIT = "&";
    private static String DEFAULT_ENCODE = "UTF-8";
    /**
     * ca證書別名
     */
    private static String SSL_KEY_ALIAS = "DIY";

    /**
     * 證書工廠
     */
    private static SSLSocketFactory sslSocketFactory = null;
    /**
     * 證書類型
     */
    private static X509TrustManager trustManager = null;

    /**
     * 正常請求
     */
    private static OkHttpClient mOkHttpClient;

    /**
     * 局域網內調用的快速請求 響應時間要求比普通正常請求快20倍
     */
    private static OkHttpClient mOkHttpClientQuick;

    /**
     * 代理請求
     */
    private static OkHttpClient mOkHttpClientProxy;

    /**
     * 單體實例類
     * @return
     * @exception/throws [異常類型] [異常說明](可選)
     * @date 2017年6月10日 下午5:00:57
     * @since 1.0.0
     */
    public static HttpClientManage getInstance()
    {
        if (instance == null)
        {
            synchronized (HttpClientManage.class)
            {
                if (instance == null)
                {
                    instance = new HttpClientManage();
                }
            }
        }
        return instance;
    }
    
    /**
     * 簡單調用: get(url)
     * 加參數調用: get(url, param)
     * 加參數同時加頭文件調用: get(url, param, header)
     * 僅加頭文件調用: get(url, null, header)
     * @param url 請求地址
     * @param params 如果有多個map傳入, 則默認第一個為參數param, 第二個為header param
     * @return
     * @exception/throws [異常類型] [異常說明](可選)
     * @date 2017年6月10日 下午5:01:50
     * @since 1.0.0
     */
    public String get(String url, Map<String, String>... params)
    {
        return getCommon(url, mOkHttpClient, params);
    }

    public String getQuick(String url, Map<String, String>... params)
    {
        return getCommon(url, mOkHttpClientQuick, params);
    }

    public String getProxy(String url, Map<String, String>... params)
    {
        if (null != mOkHttpClientProxy)
        {
            return getCommon(url, mOkHttpClientProxy, params);
        }
        return get(url, params);
    }

    public String post(String url, Map<String, String>... params)
    {
        return postCommon(url, mOkHttpClient, params);
    }

    public String postQuick(String url, Map<String, String>... params)
    {
        return postCommon(url, mOkHttpClientQuick, params);
    }

    public String postProxy(String url, Map<String, String>... params)
    {
        if (null != mOkHttpClientProxy)
        {
            return postCommon(url, mOkHttpClientProxy, params);
        }
        return post(url, params);
    }

    /**
     * 異步調用
     * 簡單調用: get(url, callback)
     * 加參數調用: get(url, callbackparam)
     * 加參數同時加頭文件調用: get(url, callback, param, header)
     * 僅加頭文件調用: get(url, callback, null, header)
     * @param url 請求地址
     * @param callback 回調函數
     * @param params 如果有多個map傳入, 則默認第一個為參數param, 第二個為header param
     * @exception/throws [異常類型] [異常說明](可選)
     * @date 2017年6月10日 下午5:02:59
     * @since 1.0.0
     */
    public void getAsyn(String url, Callback callback, Map<String, String>... params)
    {
        getCommonAsyn(url, callback, mOkHttpClient, params);
    }

    public void getQuickAsyn(String url, Callback callback, Map<String, String>... params)
    {
        getCommonAsyn(url, callback, mOkHttpClientQuick, params);
    }

    public void getProxyAsyn(String url, Callback callback, Map<String, String>... params)
    {
        if (null != mOkHttpClientProxy)
        {
            getCommonAsyn(url, callback, mOkHttpClientProxy, params);
            return;
        }
        getAsyn(url, callback, params);
    }

    public void postAsyn(String url, Callback callback, Map<String, String>... params)
    {
        postCommonAsyn(url, callback, mOkHttpClient, params);
    }

    public void postQuickAsyn(String url, Callback callback, Map<String, String>... params)
    {
        postCommonAsyn(url, callback, mOkHttpClientQuick, params);
    }

    public void postProxyAsyn(String url, Callback callback, Map<String, String>... params)
    {
        if (null != mOkHttpClientProxy)
        {
            postCommonAsyn(url, callback, mOkHttpClientProxy, params);
            return;
        }
        postAsyn(url, callback, params);
    }

    private HttpClientManage()
    {
        init();
    }

    private void init()
    {
        // 初始化靜態 如果不需要配置文件來進行參數配置,可以將此方法去掉
        initProperty();
        // 初始化CA
        initCa();
        initNormalClient();
        initQuickClient();
        initProxyClient();
    }

    /**
     * 初始化參數
     * @exception/throws [異常類型] [異常說明](可選)
     * @date 2017年6月10日 下午5:05:34
     * @since 1.0.0
     */
    private void initProperty()
    {
        //IS_INORE_CA = true;
    }

    private void initCa()
    {
        try
        {
            if (IS_INORE_CA)
            {
                trustManager = new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
                    {
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
                    {
                    }
                    @Override
                    public X509Certificate[] getAcceptedIssuers()
                    {
                        X509Certificate[] x509Certificates = new X509Certificate[0];
                        return x509Certificates;
                    }
                };
            }
            else
            {
                if (StringUtils.isEmpty(CA_PATH))
                {
                    return;
                }
                // 讀取key
                KeyStore keyStore = readKeyStore();
                if (null == keyStore)
                {
                    return;
                }
                TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory
                        .getDefaultAlgorithm());
                trustManagerFactory.init(keyStore);
                TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
                if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager))
                {
                    throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
                }
                trustManager = (X509TrustManager) trustManagers[0];
            }
            
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[] { trustManager }, null);
            sslSocketFactory = sslContext.getSocketFactory();
        }
        catch (Exception e)
        {
            LogUtil.error("initCa error.", e);
        }
    }

    private KeyStore readKeyStore()
    {
        File file = new File(CA_PATH);
        if (!file.exists())
        {
            return null;
        }

        KeyStore keyStore = null;
        CertificateFactory certificateFactory = null;
        try
        {
            certificateFactory = CertificateFactory.getInstance("X.509");
            keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
        }
        catch (Exception e1)
        {
            LogUtil.error(null, e1);
        }

        if (null == keyStore || null == certificateFactory)
        {
            return null;
        }

        InputStream inputStream = null;
        if (!file.isDirectory())
        {
            try
            {
                inputStream = new FileInputStream(file);
                addOneCer(certificateFactory, keyStore, SSL_KEY_ALIAS, inputStream);
            }
            catch (Exception e)
            {
                LogUtil.error(null, e);
            }
            finally
            {
                try
                {
                    if (inputStream != null)
                        inputStream.close();
                }
                catch (IOException e)
                {
                    LogUtil.error(null, e);
                }
            }
        }
        else
        {
            int index = 0;
            String certificateAlias;
            for (File cerFile : file.listFiles())
            {
                certificateAlias = SSL_KEY_ALIAS + Integer.toString(index++);
                try
                {
                    inputStream = new FileInputStream(cerFile);
                    addOneCer(certificateFactory, keyStore, certificateAlias, inputStream);
                }
                catch (Exception e)
                {
                    LogUtil.error(null, e);
                }
                finally
                {
                    try
                    {
                        if (inputStream != null)
                            inputStream.close();
                    }
                    catch (IOException e)
                    {
                        LogUtil.error(null, e);
                    }
                }
            }
        }

        return keyStore;
    }

    private void addOneCer(CertificateFactory certificateFactory, KeyStore keyStore, String CerAlias,
            InputStream certificate) throws KeyStoreException, CertificateException
    {
        keyStore.setCertificateEntry(CerAlias, certificateFactory.generateCertificate(certificate));
        try
        {
            if (certificate != null)
                certificate.close();
        }
        catch (IOException e)
        {
            LogUtil.error(null, e);
        }
    }

    // 初始化普通請求
    private void initNormalClient()
    {
        // 進行數據初始化
        okhttp3.OkHttpClient.Builder builder = new OkHttpClient.Builder().readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)// 設置讀取超時時間
                .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)// 設置寫的超時時間
                .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);// 設置連接超時時間
        // 有證書需要引入
        if (null != sslSocketFactory && null != trustManager)
        {
            builder.sslSocketFactory(sslSocketFactory, trustManager);
        }
        if (IS_INORE_CA)
        {
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
        }
        mOkHttpClient = builder.build();
    }

    // 初始化快速請求
    private void initQuickClient()
    {
        okhttp3.OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .readTimeout(READ_TIMEOUT_QUICK, TimeUnit.SECONDS)// 設置讀取超時時間
                .writeTimeout(WRITE_TIMEOUT_QUICK, TimeUnit.SECONDS)// 設置寫的超時時間
                .connectTimeout(CONNECT_TIMEOUT_QUICK, TimeUnit.SECONDS);// 設置連接超時時間

        // 有證書需要引入
        if (null != sslSocketFactory && null != trustManager)
        {
            builder.sslSocketFactory(sslSocketFactory, trustManager);
        }
        if (IS_INORE_CA)
        {
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
        }
        mOkHttpClientQuick = builder.build();
    }

    // 初始化代理請求
    private void initProxyClient()
    {
        if (StringUtils.isEmpty(PROXY_IP))
        {
            return;
        }
        okhttp3.OkHttpClient.Builder builder = new OkHttpClient.Builder().readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)// 設置讀取超時時間
                .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)// 設置寫的超時時間
                .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);// 設置連接超時時間

        // 有證書需要引入
        if (null != sslSocketFactory && null != trustManager)
        {
            builder.sslSocketFactory(sslSocketFactory, trustManager);
        }
        builder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(PROXY_IP, PROXY_PORT)));
        mOkHttpClientProxy = builder.build();
    }

    private String getCommon(String url, OkHttpClient okHttpClient, Map<String, String>[] params)
    {
        okhttp3.Request.Builder requestBuilder = createGetBuilder(url, params);
        return doSync(url, okHttpClient, requestBuilder, params);
    }

    /**
     * 異步請求
     * @param url
     * @param callback
     * @param mOkHttpClient
     * @param params
     * @exception/throws [異常類型] [異常說明](可選)
     * @date 2017年6月10日 下午5:05:06
     * @since 1.0.0
     */
    private void getCommonAsyn(String url, Callback callback, OkHttpClient mOkHttpClient, Map<String, String>[] params)
    {
        okhttp3.Request.Builder requestBuilder = createGetBuilder(url, params);
        doAsyn(url, callback, mOkHttpClient, requestBuilder, params);
    }

    private okhttp3.Request.Builder createGetBuilder(String url, Map<String, String>[] params)
    {
        String realUrl = url;
        Map<String, String> headers = null;
        if (null != params)
        {
            if (params.length > 0)
            {
                realUrl = buildUrl(url, params[0]);
            }
            if (params.length > 1)
            {
                headers = params[1];
            }
        }

        okhttp3.Request.Builder requestBuilder = createBuilder(realUrl, headers);
        return requestBuilder;
    }

    /**
     * 同步請求
     * @param url
     * @param okHttpClient
     * @param requestBuilder
     * @param params
     * @return
     * @exception/throws [異常類型] [異常說明](可選)
     * @date 2017年6月10日 下午5:04:29
     * @since 1.0.0
     */
    private String doSync(String url, OkHttpClient okHttpClient, okhttp3.Request.Builder requestBuilder,
            Map<String, String>[] params)
    {
        try
        {
            printRequestInfo(url, params);

            String response = okHttpClient.newCall(requestBuilder.build()).execute().body().string();

            printResponseInfo(response);
            return response;
        }
        catch (IOException e)
        {
            LogUtil.error("url:" + url + ",params:" + JsonTool.toJson(params), e);
        }
        return null;
    }

    private void printRequestInfo(String url, Map<String, String>[] params)
    {
        LogUtil.debug("url:" + url + "\n params:" + JsonTool.toJson(params).replace("\\", ""));
    }

    private void printResponseInfo(String response)
    {
        LogUtil.debug("response:" + response);
    }

    /**
     * 異步請求
     * @param url
     * @param callback
     * @param okHttpClient
     * @param requestBuilder
     * @param params
     * @exception/throws [異常類型] [異常說明](可選)
     * @since 1.0.0
     */
    private void doAsyn(String url, Callback callback, OkHttpClient okHttpClient,
            okhttp3.Request.Builder requestBuilder, Map<String, String>[] params)
    {
        printRequestInfo(url, params);
        okHttpClient.newCall(requestBuilder.build()).enqueue(callback);
        // printResponseInfo(response);
    }

    private okhttp3.Request.Builder createBuilder(String url, Map<String, String> headers)
    {
        okhttp3.Request.Builder builder = new Request.Builder().url(url);
        if (null == headers)
        {
            return builder;
        }

        for (Map.Entry<String, String> en : headers.entrySet())
        {
            builder.addHeader(en.getKey(), en.getValue());
        }
        return builder;
    }

    private String buildUrl(String url, Map<String, String> param)
    {
        if (null == param)
        {
            return url;
        }
        StringBuilder sb = new StringBuilder();
        try
        {
            for (Map.Entry<String, String> en : param.entrySet())
            {
                if (!StringUtils.isEmpty(en.getKey()) && !StringUtils.isEmpty(en.getValue()))
                {
                    sb.append(PARAM_SPLIT);
                    sb.append(URLEncoder.encode(en.getKey(), DEFAULT_ENCODE));
                    sb.append(PARAM_SPLIT_VAL);
                    sb.append(URLEncoder.encode(en.getValue(), DEFAULT_ENCODE));
                }
            }
        }
        catch (UnsupportedEncodingException e)
        {
            LogUtil.error("url=" + url, e);
        }
        if (sb.length() > 0)
        {
            if (!url.contains(PARAM_SPLIT_FIRST))
            {
                url = url + PARAM_SPLIT_FIRST;
            }
            url = url + sb.substring(1);
        }
        return url;
    }

    private String postCommon(String url, OkHttpClient okHttpClient, Map<String, String>[] params)
    {
        okhttp3.Request.Builder requestBuilder = createPostBuilder(url, params);
        return doSync(url, okHttpClient, requestBuilder, params);
    }

    private void postCommonAsyn(String url, Callback callback, OkHttpClient okHttpClient, Map<String, String>[] params)
    {
        okhttp3.Request.Builder requestBuilder = createPostBuilder(url, params);
        doAsyn(url, callback, okHttpClient, requestBuilder, params);
    }

    private okhttp3.Request.Builder createPostBuilder(String url, Map<String, String>[] params)
    {
        Map<String, String> headers = null;
        Builder formBuilder = new FormBody.Builder();
        if (null != params)
        {
            if (params.length > 0 && null != params[0])
            {
                for (Map.Entry<String, String> en : params[0].entrySet())
                {
                    formBuilder.add(en.getKey(), en.getValue());
                }
            }

            if (params.length > 1)
            {
                headers = params[1];
            }
        }
        okhttp3.Request.Builder requestBuilder = createBuilder(url, headers).post(formBuilder.build());
        return requestBuilder;
    }
    
    /**
     * 文件上傳
     * @param urlStore   上傳服務地址
     * @param file       本地文件
     * @param callback   回調函數,若無則為同步,同步則直接返回result,異步則在callback中返回上傳結果
     * @param params     第一個map為body中需要傳的參數,第二個map為頭文件中需要傳的參數
     * @return
     * @exception/throws [異常類型] [異常說明](可選)
     * @date 2018年5月11日 上午8:47:24
     */
    public String upload(String urlStore, File file, Callback callback, Map<String, String>... params)
    {
        RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream") , file);  
        okhttp3.MultipartBody.Builder mBodyBuilder = new MultipartBody.Builder()
                                                        .setType(MultipartBody.FORM)
                                                        .addFormDataPart("desc" , file.getName())
                                                        .addFormDataPart("file" , file.getName(), fileBody);
        Map<String, String> paramMap = null;
        if (null != params && params.length > 0)
        {
            paramMap = params[1];
        }                                                ;
        if (null != paramMap)
        {
            for (Map.Entry<String, String> en : paramMap.entrySet())
            {
                mBodyBuilder.addFormDataPart(en.getKey(), en.getValue());
            }
        }
        Map<String, String> headMap = null;
        if (null != params && params.length > 1)
        {
            headMap = params[1];
        }
         
        okhttp3.Request.Builder requestBuilder = createBuilder(urlStore, headMap);
        requestBuilder.post(mBodyBuilder.build());
        
        if (null == callback)
        {
            //同步
            return doSync(urlStore, mOkHttpClient, requestBuilder, params);
        }
        else
        {
            //異步
            doAsyn(urlStore, callback, mOkHttpClient, requestBuilder, params);
            return null;
        }
    }
    

    
}

是否https證書驗證(默認不做證書校驗,建議生成環境一定要做證書校驗,哪怕是導入私有證書),配置

IS_INORE_CA = false

導入私有證書,配置

CA_PATH 配置CA證書(就是瀏覽器證書導出的那個證書)路徑即可

設置代理服務器,配置

PROXY_IP和PROXY_PORT即可(默認不采用代理)

上傳文件

String rs = HttpClientManage.getInstance().upload(urlStore, file, null, null);

其中rs為同步返回的結果。

OKHttp官網不建議使用多個實例,因為每個實例都自己配置了線程管理,所以項目中不涉及基礎信息的改動(比如,超時時間,證書等),建議就共用一個實例。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM