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