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官网不建议使用多个实例,因为每个实例都自己配置了线程管理,所以项目中不涉及基础信息的改动(比如,超时时间,证书等),建议就共用一个实例。

猜你喜欢

转载自www.cnblogs.com/zhuri/p/9022909.html