package com.base.httpclient.core;
import java.net.HttpURLConnection;
import android.annotation.SuppressLint;
/**
* Lightweight HTTP client that facilitates GET, POST, PUT, and DELETE requests
* using {@link HttpURLConnection}. Extend this class to support specialized
* content and response types (see {@link BasicHttpClient} for an example). To
* enable streaming, buffering, or other types of readers / writers, set an
* alternate {@link RequestHandler}.
*
* @author David M. Chandler
*/
@SuppressLint("NewApi")
public abstract class AbsHttpClient {
private int maxRetries = 3;
public static final String BOUNDARY = "------issmobile------";
public static final String CONTENT_TYPE_URLENCODED = "application/x-www-form-urlencoded;charset=UTF-8";
public static final String CONTENT_TYPE_MULTIPART = "multipart/form-data; boundary=" + BOUNDARY;
public static final String CRLF = "\r\n";
/**
* 连接超时时间,默认 2s
*/
protected int connectionTimeout = 2000;
/**
* 读取数据超时时间,默认8s
*/
protected int readTimeout = 8000;
/**
* Execute a HEAD request and return the response. The supplied parameters
* are URL encoded and sent as the query string.
*
* @param path
* @param params
* @return Response object
* @throws HttpRequestException
*/
public abstract HttpResponse head(String path, ParameterList params) throws HttpRequestException;
/**
* Execute a GET request and return the response. The supplied parameters
* are URL encoded and sent as the query string.
*
* @param path
* @param params
* @return Response object
* @throws HttpRequestException
*/
public abstract HttpResponse get(String path, ParameterList params) throws HttpRequestException;
public abstract HttpResponse get(String path, ParameterList params,boolean isUrlEncode) throws HttpRequestException;
/**
* Execute a POST request with parameter map and return the response.
*
* @param path
* @param params
* @return Response object
* @throws HttpRequestException
*/
public abstract HttpResponse post(String path, ParameterList params) throws HttpRequestException;
/**
* Execute a POST request with a chunk of data and return the response. To
* include name-value pairs in the query string, add them to the path
* argument or use the constructor in {@link HttpPost}. This is not a common
* use case, so it is not included here.
*
* @param path
* @param contentType
* @param data
* @return Response object
* @throws HttpRequestException
*/
public abstract HttpResponse post(String path, String contentType, byte[] data)
throws HttpRequestException;
/**
* Execute a PUT request with the supplied content and return the response.
* To include name-value pairs in the query string, add them to the path
* argument or use the constructor in {@link HttpPut}. This is not a common
* use case, so it is not included here.
*
* @param path
* @param contentType
* @param data
* @return Response object
* @throws HttpRequestException
*/
public abstract HttpResponse put(String path, String contentType, byte[] data)
throws HttpRequestException;
/**
* Execute a DELETE request and return the response. The supplied parameters
* are URL encoded and sent as the query string.
*
* @param path
* @param params
* @return Response object
* @throws HttpRequestException
*/
public abstract HttpResponse delete(String path, ParameterList params)
throws HttpRequestException;
/**
* 当发生访问超时异常时,在指定访问次数的范围内,自动尝试再次访问
*
* @param httpMethod
* @return Response object, may be null
* @throws HttpRequestException
*/
public HttpResponse tryMany(HttpMethod httpMethod) throws HttpRequestException {
HttpResponse res = null;
while (httpMethod.numTries < maxRetries) {
try {
setConnectionTimeout(httpMethod.getNextTimeout());
res = execute(httpMethod);
if (res != null) {
return res;
}
} catch (HttpRequestException e) {
if (e.isTimeOutException() && httpMethod.numTries < (maxRetries - 1)) {
continue;
} else {
throw e;
}
} finally {
httpMethod.numTries++;
}
}
return null;
}
/**
* Set maximum number of retries to attempt, capped at 18. On the 18th
* retry, the connection timeout will be 4,181 sec = 1 hr 9 min.
*
* @param maxRetries
*/
public void setMaxRetries(int maxRetries) {
if (maxRetries < 1 || maxRetries > 18) {
throw new IllegalArgumentException("Maximum retries must be between 1 and 18");
}
this.maxRetries = maxRetries;
}
/**
* 用指定的HttpMethod请求数据,默认使用BasicRequestHandler
*
* @param httpMethod
* @return
* @throws HttpRequestException
*/
protected HttpResponse execute(HttpMethod httpMethod) throws HttpRequestException {
return execute(httpMethod, new BasicRequestHandler() {
});
}
/**
* 用指定的HttpMethod和RequestHandler请求数据
*
* @param httpMethod
* @param requestHandler
* @return
* @throws HttpRequestException
*/
protected HttpResponse execute(HttpMethod httpMethod, RequestHandler requestHandler)
throws HttpRequestException {
HttpURLConnection uc = null;
HttpResponse httpResponse = null;
long startTime = System.currentTimeMillis();
try {
httpMethod.isConnected = false;
uc = requestHandler.openConnection(httpMethod.getRequestUrl());
uc.setConnectTimeout(connectionTimeout);
uc.setReadTimeout(readTimeout);
requestHandler.prepareConnection(uc, httpMethod);
requestHandler.writeHeaders(uc, httpMethod);
uc.connect();
httpMethod.isConnected = true;
if (uc.getDoOutput()) {
requestHandler.writeStream(uc, httpMethod);
}
if (uc.getDoInput()) {
httpResponse = requestHandler.readInputStream(uc);
} else {
httpResponse = new HttpResponse(uc, null);
}
} catch (Exception e) {
if (isTimeoutException(startTime, httpMethod.isConnected)) {
throw new HttpRequestException(e, HttpRequestException.TIME_OUT_EXCEPTION);
} else {
throw new HttpRequestException(e, HttpRequestException.OTHER_EXCEPTION);
}
} finally {
if (uc != null) {
uc.disconnect();
}
httpMethod.isConnected = false;
}
return httpResponse;
}
/**
* Convenience method creates a new ParameterMap to hold query params
*
* @return Parameter map
*/
public ParameterList newParams() {
return new ParameterList();
}
// /**
// * Returns the {@link CookieManager} associated with this client.
// *
// * @return CookieManager
// */
// public static CookieManager getCookieManager() {
// return (CookieManager) CookieHandler.getDefault();
// }
//
// /**
// * Initialize the app-wide {@link CookieManager}. This is all that's
// * necessary to enable all Web requests within the app to automatically
// send
// * and receive cookies.
// */
// protected static void ensureCookieManager() {
// if (CookieHandler.getDefault() == null) {
// CookieHandler.setDefault(new CookieManager());
// }
// }
/**
* 判断是否超时
*
* @param startTime
* @param isConnected
* @return
*/
protected boolean isTimeoutException(long startTime, boolean isConnected) {
long elapsedTime = System.currentTimeMillis() - startTime + 10; // fudge
if (isConnected) {
return elapsedTime >= readTimeout;
} else {
return elapsedTime >= connectionTimeout;
}
}
/**
* 设置连接超时时间
*
* @param connectionTimeout
*/
public void setConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
/**
* 设置读取数据超时时间
*
* @param readTimeout
*/
public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
}
}