package com.cundong.izhihu.http;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.util.ArrayList;
import javax.net.ssl.SSLHandshakeException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.scheme.PlainSocketFactory;
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.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.text.TextUtils;
import com.cundong.izhihu.exception.ZhihuIOException;
import com.cundong.izhihu.exception.ZhihuOtherException;
import com.cundong.izhihu.util.Logger;
/**
* 类说明: HttpClient工具类
*
* @date 2014-1-4
* @version 1.0
*/
public class HttpClientUtils {
private static final String CHARSET = HTTP.UTF_8;
/**
* 最大连接数
*/
public final static int MAX_TOTAL_CONNECTIONS = 200;
/**
* 每个路由最大连接数
*/
public final static int MAX_ROUTE_CONNECTIONS = 200;
/**
* 获取连接的最大等待时间
*/
public final static int RETRIVE_CONNECT_TIMEOUT = 6 * 1000;
private static final int RETRIED_TIME = 3;
private static final int COMMON_TIMEOUT = 6 * 1000;
private static Logger mLogger = Logger.getLogger();
private static volatile DefaultHttpClient customerHttpClient = null;
private HttpClientUtils() {
}
public static HttpClient getInstance(Context context) {
if (customerHttpClient == null) {
synchronized (HttpClientUtils.class) {
if (customerHttpClient == null) {
HttpParams params = new BasicHttpParams();
// 设置一些基本参数
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);
HttpProtocolParams.setUserAgent(params, System
.getProperties().getProperty("http.agent")
+ " Mozilla/5.0 Firefox/26.0");
/* 连接超时 */
HttpConnectionParams.setConnectionTimeout(params, COMMON_TIMEOUT);
/* 请求超时 */
HttpConnectionParams.setSoTimeout(params, COMMON_TIMEOUT);
// 支持http和https两种模式
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
schReg.register(new Scheme("https", getSSLSocketFactory(),
443));
// 使用线程安全的连接管理来创建HttpClient
ClientConnectionManager conMgr = new ThreadSafeClientConnManager(
params, schReg);
customerHttpClient = new DefaultHttpClient(conMgr, params);
customerHttpClient.setHttpRequestRetryHandler(requestRetryHandler);
ConnManagerParams.setMaxTotalConnections(params, MAX_TOTAL_CONNECTIONS);
// 设置每个路由最大连接数
ConnPerRouteBean connPerRoute = new ConnPerRouteBean(MAX_ROUTE_CONNECTIONS);
ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);
// 设置获取连接的最大等待时间
ConnManagerParams.setTimeout(params, RETRIVE_CONNECT_TIMEOUT);
ConnectivityManager manager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkinfo = manager.getActiveNetworkInfo();
String net = networkinfo != null ? networkinfo
.getExtraInfo() : null;
// wifi的值为空
if (!TextUtils.isEmpty(net)) {
String proxyHost = getDefaultHost();
if (!TextUtils.isEmpty(proxyHost)) {
HttpHost proxy = new HttpHost(proxyHost, getDefaultPort(), "http");
customerHttpClient.getParams().setParameter(
ConnRoutePNames.DEFAULT_PROXY, proxy);
}
}
}
}
}
return customerHttpClient;
}
private static SSLSocketFactory getSSLSocketFactory() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore
.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sslSocketFactory = new TrustAllSSLSocketFactory(
trustStore);
sslSocketFactory
.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
return sslSocketFactory;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 异常自动恢复处理, 使用HttpRequestRetryHandler接口实现请求的异常恢复
*
*/
private static HttpRequestRetryHandler requestRetryHandler = new HttpRequestRetryHandler() {
@Override
public boolean retryRequest(IOException exception, int executionCount,
HttpContext context) {
// 设置恢复策略,在发生异常时候将自动重试N次
if (executionCount >= RETRIED_TIME) {
// Do not retry if over max retry count
Logger.getLogger().e(
"Do not retry if over max retry count:"
+ executionCount);
return false;
}
if (exception instanceof NoHttpResponseException) {
// Retry if the server dropped connection on us
Logger.getLogger()
.i("Retry if the server dropped connection on us:exception instanceof NoHttpResponseException");
return true;
}
if (exception instanceof SSLHandshakeException) {
// Do not retry on SSL handshake exception
Logger.getLogger().e(
"Do not retry on SSL handshake SSLHandshakeException ");
return false;
}
HttpRequest request = (HttpRequest) context
.getAttribute(ExecutionContext.HTTP_REQUEST);
boolean idempotent = (request instanceof HttpEntityEnclosingRequest);
if (!idempotent) {
// Retry if the request is considered idempotent
Logger.getLogger().i(
"Retry if the request is considered idempotent");
return true;
}
return false;
}
};
/**
* get请求
*
* @param context
* @param url
* @param params
* @param responseListener
*/
public static void get(final Context context, String url, Bundle params,
ResponseListener responseListener) {
if (params != null) {
if (url.contains("?")) {
url = url + "&" + UrlUtils.encodeUrl(params);
} else {
url = url + "?" + UrlUtils.encodeUrl(params);
}
}
Logger.getLogger().d("GET:" + url);
HttpGet request = new HttpGet(url);
HttpClient httpClient = getInstance(context);
// 解决:HttpClient WARNING: Cookie rejected: Illegal domain attribute
httpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY,
CookiePolicy.BROWSER_COMPATIBILITY);
String response = "";
try {
response = httpClient.execute(request, new BasicResponseHandler());
if (!TextUtils.isEmpty(response)) {
responseListener.onComplete(response);
} else {
responseListener.onComplete("");
}
} catch (IOException e) {
e.printStackTrace();
if (e instanceof ConnectTimeoutException) {
mLogger.e("error ConnectTimeoutException.");
}
mLogger.e("error begin.");
mLogger.e("error params:");
mLogger.e("error.url(GET):" + url);
mLogger.e("error.getMessage:" + e.getMessage());
mLogger.e("error end.");
responseListener.onFail(new ZhihuIOException(
"request url IOException", e));
} catch (Exception e) {
e.printStackTrace();
mLogger.e("error:" + e.getMessage());
responseListener.onFail(new ZhihuOtherException(
"request url Exception", e));
}
}
/**
* get请求,返回字符串
*
* @param context
* @param url
* @param params
*/
public static String get(Context context, String url, Bundle params)
throws IOException, Exception {
if (params != null) {
if (url.contains("?")) {
url = url + "&" + UrlUtils.encodeUrl(params);
} else {
url = url + "?" + UrlUtils.encodeUrl(params);
}
}
Logger.getLogger().d("GET:" + url);
HttpGet request = new HttpGet(url);
HttpClient httpClient = getInstance(context);
// 解决:HttpClient WARNING: Cookie rejected: Illegal domain attribute
httpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY,
CookiePolicy.BROWSER_COMPATIBILITY);
return httpClient.execute(request, new BasicResponseHandler());
}
/**
* get a stream from web
*
* @param context
* @param url
* @param params
*/
public static InputStream getStream(Context context, String url, Bundle params)
throws IOException, Exception {
if (params != null) {
if (url.contains("?")) {
url = url + "&" + UrlUtils.encodeUrl(params);
} else {
url = url + "?" + UrlUtils.encodeUrl(params);
}
}
Logger.getLogger().d("GET:" + url);
HttpGet request = new HttpGet(url);
HttpClient httpClient = getInstance(context);
// 解决:HttpClient WARNING: Cookie rejected: Illegal domain attribute
httpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY,
CookiePolicy.BROWSER_COMPATIBILITY);
HttpResponse response = httpClient.execute(request);
return response.getEntity().getContent();
}
/**
* post请求
*
* @param context
* @param url
* @param params
* @param responseListener
*/
public static void post(Context context, String url,
ArrayList<NameValuePair> params, ResponseListener responseListener) {
try {
mLogger.d("POST:" + url);
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params,
CHARSET);
HttpPost request = new HttpPost(url);
request.setEntity(entity);
HttpClient client = getInstance(context);
HttpResponse response = client.execute(request);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity resEntity = response.getEntity();
String ret = (resEntity == null) ? null : EntityUtils.toString(
resEntity, CHARSET);
responseListener.onComplete(ret);
} else {
responseListener.onComplete("");
}
} catch (IOException e) {
e.printStackTrace();
mLogger.e("error.url(POST):" + url);
responseListener.onFail(new ZhihuIOException(
"request url IOException", e));
} catch (Exception e) {
e.printStackTrace();
mLogger.e("error:" + e.getMessage());
responseListener.onFail(new ZhihuOtherException(
"request url Exception", e));
}
}
/**
* post请求,获取一个stream
*
* @param context
* @param url
* @param params
*/
public static InputStream post(Context context, String url,
ArrayList<NameValuePair> params) {
InputStream in = null;
try {
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params,
CHARSET);
HttpPost request = new HttpPost(url);
request.setEntity(entity);
HttpClient client = getInstance(context);
HttpResponse response = client.execute(request);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity resEntity = response.getEntity();
in = (resEntity == null) ? null : resEntity.getContent();
}
} catch (IOException e) {
e.printStackTrace();
mLogger.e("error:" + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
mLogger.e("error:" + e.getMessage());
}
return in;
}
/**
* post一个字符串到服务器
*
* @param context
* @param url
* @param jsonString
* @param responseListener
*/
public static void post(Context context, String url, String jsonString,
ResponseListener responseListener) {
try {
HttpPost request = new HttpPost(url);
StringEntity entity = new StringEntity(jsonString);
request.setEntity(entity);
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
mLogger.d("POST:" + url);
mLogger.d("BODY:" + jsonString);
HttpClient client = getInstance(context);
HttpResponse response = client.execute(request);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity resEntity = response.getEntity();
String ret = (resEntity == null) ? null : EntityUtils.toString(
resEntity, CHARSET);
responseListener.onComplete(ret);
} else {
responseListener.onComplete("");
}
} catch (IOException e) {
e.printStackTrace();
mLogger.e("error begin.");
mLogger.e("error POST BODY:");
mLogger.e("error.url(POST):" + url);
mLogger.e("error.getMessage:" + e.getMessage());
mLogger.e("error end.");
responseListener.onFail(new ZhihuIOException(
"request url IOException", e));
} catch (Exception e) {
e.printStackTrace();
mLogger.e("error:" + e.getMessage());
responseListener.onFail(new ZhihuOtherException(
"request url Exception", e));
}
}
/**
* post请求一个byte[] 数组到服务器
*
* @param context
* @param url
* @param bytes
* @param responseListener
*/
public static void post(Context context, String url, byte[] bytes,
ResponseListener responseListener) {
HttpPost request = new HttpPost(url);
request.setEntity(new ByteArrayEntity(bytes));
try {
mLogger.d("POST:" + url);
HttpClient client = getInstance(context);
HttpResponse response = client.execute(request);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity resEntity = response.getEntity();
String ret = (resEntity == null) ? null : EntityUtils.toString(
resEntity, CHARSET);
responseListener.onComplete(ret);
} else {
responseListener.onComplete("");
}
} catch (IOException e) {
e.printStackTrace();
mLogger.e("error.url(POST):" + url);
responseListener.onFail(new ZhihuIOException(
"request url IOException", e));
} catch (Exception e) {
e.printStackTrace();
mLogger.e("error:" + e.getMessage());
responseListener.onFail(new ZhihuOtherException(
"request url Exception", e));
}
}
@SuppressWarnings("deprecation")
private static String getDefaultHost() {
return android.net.Proxy.getDefaultHost();
}
@SuppressWarnings("deprecation")
private static int getDefaultPort() {
return android.net.Proxy.getDefaultPort();
}
}